在django中,多种相似的view视图会造成代码的冗余。这时候,可以用django中的通用视图来解决这个问题。
例如:
# polls/urls
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
# polls/views
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
def results(request, question_id):
question = get_object_or_404(Question, pk = question_id)
return render(request, 'polls/results.html',{'question': question})
这种视图有很多相似的地方。
其实,这类视图都有一个共通的地方,从根据url提供的参数从数据库中获取数据,加载模板文件并且返回渲染后的模板。django中的通用视图可以解决这个问题。
先来看看用generic修改后的样子:
# polls/urls
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
# polls/views
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
# 导入的通用视图
from .models import Choice, Question
# 使用Listview
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
# 使用DetailView
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
两个通用视图的区别:
ListView显示一个对象列表。
DetailView显示一个特定类型对象的详细信息页面。
下面解释以下更改的内容:
1、由于DetailView需要从url中获取主键值,所以在urls中将question_id更改为pk(主键值);
2、在默认情况下,通用视图 DetailView 使用一个叫做 < app name>/< model name>_detail.html 的模板。在例子中,它将使用 “polls/Question_detail.html” 模板。template_name 属性是用来告诉 Django 使用一个指定的模板名字,而不是自动生成的默认名字。类似地,ListView 使用一个叫做 < app name>/< model name>_list.html 的默认模板;使用 template_name 来告诉 ListView 使用已经存在的 “polls/index.html” 模板。
修改中遇到的问题
1、
TypeError: __init__() takes 1 positional argument but 2 were given
解决方法:没有添加as_view()方法(自动查找指定方法)
修改前:
path('', views.IndexView, name='index'),
修改后:
path('', views.IndexView.as_view(), name='index'),
2、
Generic detail view ResultsView must be called with either an object pk or a slug.
没有修改question_id 为pk 因为通用视图DetailView已经制订了model 所以需要提供pk(主键值)。
修改前:
path('<int:question_id>/results/', views.ResultsView.as_view(), name='results'),
修改后:
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),