對Django中通用視圖generic的一些理解

在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'),
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章