[TOC] >[success] # ListView ~~~ 先来看ListView的流程: 1.请求到达之后,首先会调用distpatch进行分发。 2.接着会调用get方法 3.在get请求中,首先会调用get_queryset方法,拿到数据源 4.接着继续调用get_context_data方法,拿到需要渲染到模板中的数据 5.在get_context_data中,首先会去调用get_paginate_by拿到每页数据 6.接着调用get_context_object_name拿到要渲染到模板中的这个queryset名称 * 7.然后调用paginate_queryset进行分页处理 * 8.把拿到的数据转为dict,返回 9.调用render_to_response渲染数据到页面中 10.在render_to_response中会调用get_tempalte_names拿到模板名 11.然后把request, context, template_name等传递到模板中 ~~~ * 文档中的截图 ![](https://box.kancloud.cn/eb3d041fa1f2b5e5883ba214462f938a_644x466.png) * 文档中的用法 ~~~ from django.views.generic.list import ListView from django.utils import timezone from articles.models import Article class ArticleListView(ListView): model = Article def get_context_data(self, **kwargs): context = super(ArticleListView, self).get_context_data(**kwargs) context['now'] = timezone.now() return context ~~~ ~~~ from django.conf.urls import url from article.views import ArticleListView urlpatterns = [ url(r'^$', ArticleListView.as_view(), name='article-list'), ] ~~~ ~~~ <h1>Articles</h1> <ul> {% for article in object_list %} <li>{{ article.pub_date|date }} - {{ article.headline }}</li> {% empty %} <li>No articles yet.</li> {% endfor %} </ul> ~~~ * 源码中初始化参数 ~~~ allow_empty = True queryset = None model = None paginate_by = None paginate_orphans = 0 context_object_name = None paginator_class = Paginator page_kwarg = 'page' ordering = None ~~~ >[success] # 博客中的ListView 案例 >[danger] ##### url设计 ~~~ from django.conf.urls import url from django.contrib import admin from blong.views import IndexView, CategoryView, TagView, PostView from config.views import links from .custom_site import custom_site urlpatterns = [ url(r"^$", IndexView.as_view()), url(r'^category/(?P<category_id>\d+)/$', CategoryView.as_view(), name="category"), url(r'^tag/(?P<tag_id>\d+)/$', TagView.as_view(), name="tag"), url(r'^post/(?P<pk>\d+)/$', PostView.as_view(),name="detail"), url(r'^links/$', links), url(r'^admin/', admin.site.urls), url(r'^cus_admin/', custom_site.urls), ] ~~~ >[danger] ##### 分析讲解 ~~~ 1.博客中首页数据来自post 数据,不过来源有三种分别是,category,tag,all,依次 对应,分类,标签,和所有 也就是查询的都是post 只不过对应三种状态 2.可以自定义一个基类,对应三个子类,三个子类分别操作 category,tag,all,三种 状态 分类,标签,和所有都和post 有关联 3.想编辑查询语句 重写get_queryset 方法 4.model 声明的是对应的数据库类 5.template_name 对应的模板信息 6.context_object_name 对应html 页面k 值,当我们用模板语言的时候需要告诉接受 查询k名称 7.paginate_by 分页的时候页面显示的条数 ~~~ >[danger] ##### 通用类 ~~~ 1.这个通用类在博客系统中的逻辑是,上下标题栏,侧边栏,最新评价,和最新文章 2.多个类都用了这部分可以做提取,其中get_category_context()做的是二次提取 3.当我们想返回的数据大于,系统帮我们默认通过get_queryset()查询返回的数据还要 多的时候 ,重写get_context_data ~~~ ~~~ from pprint import pprint as pp from django.shortcuts import render from django.http import Http404 from django.core.paginator import Paginator,EmptyPage from django.views.generic import ListView, DetailView,FormView from django.db import connection from .models import Post, Tag, Categroy from config.models import SideBar from comment.models import Comment # Create your views here. class CommonMixin: def get_category_context(self): categories = Categroy.objects.filter(status=1) # TODO: fix magic number nav_cates = [] cates = [] for cate in categories: if cate.is_nav: nav_cates.append(cate) else: cates.append(cate) return { 'nav_cates': nav_cates, 'cates': cates, } def get_context_data(self, **kwargs): side_bar = SideBar.objects.filter(status=1) recently_posts = Post.objects.filter(status=1)[:10] recently_comments = Comment.objects.filter(status=1)[:10] kwargs.update({ 'side_bars': side_bar, 'recently_posts': recently_posts, "recently_comments": recently_comments }) kwargs.update(self.get_category_context()) return super(CommonMixin, self).get_context_data(**kwargs) # ** 解码 ~~~ >[danger] ##### 基类代码 ~~~ class BasePostsView(CommonMixin,ListView): model = Post template_name = 'blog/list.html' context_object_name = "posts" paginate_by = 3 allow_empty = True ~~~ >[danger] ##### 首页代码 ~~~ 1.get_queryset()默认查询配置项所有数据,也就是 object.all() ~~~ ~~~ class IndexView(BasePostsView): pass ~~~ >[danger] ##### 分类数据展示代码 ~~~ 1.重写get_queryset() 方法,因为分类数据是去查询和post 一对多关系的category_id 2.我们在url 用了捕获正则,要获取 正则的值self.kwargs.get('category_id') 3.一定要先super 父类,通过父类的all,在fittler 过滤查询我们想要的数据 4.继承了基类 BasePostsView ~~~ ~~~ class CategoryView(BasePostsView): def get_queryset(self): qs = super(CategoryView, self).get_queryset() cate_id = self.kwargs.get('category_id') qs = qs.filter(category_id=cate_id) return qs ~~~ >[danger] ##### 标签数据展示代码 ~~~ 1.当我们想查询的数据不一定是,我们定义model 数据,可以重写get_queryset()方法 2.熟练使用当获取单个对象用get 3.捕获单个对象get 异常用Tag.DoesNotExist ~~~ ~~~ class TagView(BasePostsView): def get_queryset(self): tag_id = self.kwargs.get("tag_id") try: tag = Tag.objects.get(id=tag_id) except Tag.DoesNotExist: return [] posts = tag.post_set.all() return posts ~~~