Django中class-based view的使用示例
代碼如下:
""" class-based view """
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.views.generic import ListView, DetailView
from config.models import SideBar
from .models import Post, Tag, Category
# 公共view
class CommonViewMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'sidebars': SideBar.get_all(),
})
context.update(Category.get_navs())
return context
# 處理首頁的HTTP請求view
class IndexView(CommonViewMixin, ListView):
queryset = Post.latest_posts() # 獲取數據
paginate_by = 5 # 每頁顯示的記錄數量
context_object_name = 'post_list' # 設置queryset的變量名稱,用於在模板中調用
template_name = 'blog/list.html' # 渲染使用的模板文件
# category列表頁view
class CategoryView(IndexView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category_id = self.kwargs.get('category_id')
category = get_object_or_404(Category, pk=category_id)
context.update({
'category': category,
})
return context
def get_queryset(self):
""" 重寫queryset,根據分類過濾 """
queryset = super().get_queryset() # 此處返回IndexView的queryset屬性
category_id = self.kwargs.get('category_id')
return queryset.filter(category_id=category_id) # 關鍵字參數:一對一外鍵category_id
# tag列表頁view
class TagView(IndexView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tag_id = self.kwargs.get('tag_id')
tag = get_object_or_404(Tag, pk=tag_id)
context.update({
'tag': tag,
})
return context
def get_queryset(self):
""" 重寫queryset,根據標籤過濾"""
queryset = super().get_queryset() # 此處返回IndexView的queryset屬性
tag_id = self.kwargs.get('tag_id')
return queryset.filter(tag__id=tag_id) # 關鍵字參數:多對多外鍵要tag__id
# 文章詳情頁view
class PostDetailView(CommonViewMixin, DetailView):
queryset = Post.latest_posts()
template_name = 'blog/detail.html'
context_object_name = 'post' # 設置傳遞到模板文件的變量名稱
pk_url_kwarg = 'post_id' # 在DetailView中,會根據這個參數來過濾數據,如:post = queryset.filter(pk=post_id)
# 搜索列表頁view
class SearchView(IndexView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'keyword': self.request.GET.get('keyword', '')
})
return context
def get_queryset(self):
queryset = super().get_queryset()
keyword = self.request.GET.get('keyword', '')
if not keyword:
return queryset
return queryset.filter(Q(title__icontains=keyword) | Q(desc__icontains=keyword))
# 根據作者過濾的列表頁view
class AuthorView(IndexView):
def get_queryset(self):
queryset = super().get_queryset()
author_id = self.kwargs.get('owner_id')
return queryset.filter(owner_id=author_id)
代碼分析:
代碼中的註釋已經很好地解釋了上面的代碼。
1、class CommonViewMixin:
在這個公共類view,我們通過重寫get_context_data函數來獲取一些公用的數據,這些數據在各種頁面中都需要展示,如:導航欄、側邊欄的數據
2、class IndexView(CommonViewMixin, ListView):
這個類繼承了CommonViewMixin, ListView這兩個類,實現了首頁列表頁的視圖函數。
通過設置queryset屬性來獲取數據庫中的文章數據:
queryset = Post.latest_posts() # 獲取數據
其他的屬性說明在代碼中有註釋。
3、對於CategoryView(IndexView)、TagView(IndexView)、SearchView(IndexView)、AuthorView(IndexView):
這幾個類view都繼承了類IndexView(CommonViewMixin, ListView)。
(1)通過重寫get_context_data()函數來添加額外要獲取的數據。
(2)通過重寫get_queryset(self)函數來對IndexView(CommonViewMixin, ListView)中獲取到queryset數據進行過濾。原因如下:
在CategoryView(IndexView)、TagView(IndexView)、SearchView(IndexView)、AuthorView(IndexView)這幾個類get_queryset(self)函數中調用了父類的get_queryset(self)函數:
queryset = super().get_queryset()
因爲在IndexView(CommonViewMixin, ListView)中設置了queryset屬性:
queryset = Post.latest_posts() # 獲取數據
所以CategoryView(IndexView)、TagView(IndexView)、SearchView(IndexView)、AuthorView(IndexView)的這行代碼:
queryset = super().get_queryset()
返回的即是父類IndexView(CommonViewMixin, ListView)的queryset屬性。
接着,就可以對queryset 數據進行過濾了。