在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'),