Django中class-based view的使用示例

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章