当一些视图函数存在大量相似代码或功能时,可以考虑使用Djangle自带的通用视图。衔接上一篇 为Django app创建视图(下)
通用视图
泛型视图将通用模式抽象到甚至不需要编写Python代码就可以编写应用程序的程度。
一般有如下步骤:
-
转换URLconf。
-
删除一些旧的、不需要的视图。
-
在Django的通用视图的基础上引入新视图。
转换URLconf
打开文件 polls/urls.py,做如下修改:
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'),
]
这里做的主要修改,是将第二和第三个path()里的<int:question_id>
改成了<int:pk>
。
修改视图函数
修改polls/views.py如下:
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
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]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
... # 不变
我们在这里使用两个通用视图:ListView和DetailView。这两个视图分别抽象了“显示对象列表”和“显示特定类型对象的详细页”的概念。
每个视图函数都需要知道它们作用在哪个视图上,通过model属性来设置。
DetailView通用视图获取的主键名为pk,所以将<int:question_id>
改成了<int:pk>
。
默认情况下,DeatilView通用视图使用的模板命名规则为
< app name>/< model name>_detail.html
所以在本例中,使用polls/question_detail.html。
template_name用于告诉视图函数指定模板的名称
在早前的index()视图函数中,代码如下:
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)
更改后的index()视图函数:
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]
这里很重要的变化是重写了get_queryset()方法以及context_object_name = ‘latest_question_list’,因为通用视图本身会自动生成返回对象的名字,比如会自动生成question_list,这样html里因为名字问题可能会获取不到返回值。所以如果想覆盖掉这个名字,就用这句话,赋值即为html里接收到的对象的名字。如果不加这句话,就需要去到html里将变量名称改为question_list。
总结
通用视图的好处就是使代码更加的简洁,需要注意的就是在使用过程中,需要通过model和template_name来指定模型和模板,另外,如果需要特定查询,需要重写get_queryset()方法。通用函数适合从项目刚开始时就考虑好哪里适合采用,以此来简化开发。