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 数据进行过滤了。