文章目录

  • 0.思路引导
  • 1.ListView
  • 2.将 index 视图函数改写为类视图
  • 3.将 category 视图函数改写为类视图
  • 4.将 archive 视图函数改写成类视图
  • 5.将 tag 视图函数改写成类视图
  • 6.DetailView
  • 7.将DetailView视图函数改写成类视图

0.思路引导

1)在开发网站的过程中,有一些视图函数虽然处理的对象不同,但是其大致的代码逻辑是一样的。比如一个博客和一个论坛,通常其首页都是展示一系列的文章列表或者帖子列表;

2)对处理首页的视图函数来说,其处理的逻辑即:首先从数据库取出文章或者帖子列表,然后将这些数据传递给模板并渲染模板;

3)于是,django 把这些相同的逻辑代码抽取了出来,写成了一系列的通用视图函数,即基于类的通用视图(Generic Class Based View);

4)使用类视图是 django 推荐的做法,熟悉了类视图的使用方法后,能够减少视图函数的重复代码,节省开发时间。

接下来就让我们把博客应用中的视图函数改成基于类的通用视图。

1.ListView

在我们的博客应用中,有几个视图函数是从数据库中获取文章(Post)列表数据的:

文件位置:blog/views.py

def index(request):# ...def archive(request, year, month):# ...def category(request, pk):# ...def tag(request, pk):# ...

这些视图函数都是从数据库中获取文章(Post)列表,唯一的区别就是获取的文章列表可能不同。比如 index 获取全部文章列表,category 获取某个分类下的文章列表。

针对这种从数据库中获取某个模型列表数据(比如这里的 Post 列表)的视图,Django 专门提供了一个 ListView 类视图。

2.将 index 视图函数改写为类视图

文件位置:blog/views.py

原视图函数如下:


def index(request):post_list = Post.objects.all()return render(request, 'blog/index.html', context={'post_list': post_list})

修改成如下所示:

from django.views.generic import ListViewclass IndexView(ListView):model = Posttemplate_name = 'blog/index.html'context_object_name = 'post_list'

注意:

1)要写一个类视图,首先需要继承 django 提供的某个类视图。至于继承哪个类视图,需要根据你的视图功能而定。比如这里 IndexView 的功能是从数据库中获取文章(Post)列表,ListView 就是从数据库中获取某个模型列表数据的,所以 IndexView 继承 ListView。

2)model:将 model 指定为 Post,告诉 django 我要获取的模型是 Post。

3)template_name:指定这个视图即将去渲染的模板。

4)context_object_name:指定获取的模型列表数据保存的变量名,这个变量会被传递给模板。

接下来,需要更改blog 的 URL 配置。

文件位置:blog/urls.py

原文件如下:

app_name = 'blog'
urlpatterns = [path('', views.index, name='index'),...
]

修改为如下所示:

app_name = 'blog'
urlpatterns = [path('', views.IndexView.as_view(), name='index'),...
]

注意:
1)URL中每一个path对应着一个视图函数,这样当用户访问这个 URL 时,Django 就知道调用哪个视图函数去处理这个请求了。

2)在 Django 中 URL 模式的配置方式就是通过 url 函数将 URL 和视图函数绑定。比如 path(’’, views.index, name=‘index’),它的第一个参数是 URL 模式,第二个参数是视图函数 index。

3)对 url 函数来说,第二个参数传入的值必须是一个函数。而 IndexView 是一个类,不能直接替代 index 函数。好在将类视图转换成函数视图非常简单,只需调用类视图的 as_view() 方法即可。

3.将 category 视图函数改写为类视图

文件位置:blog/views.py

原视图函数如下:

def category(request, pk):"""定义 分类 视图"""# 记得在开始部分导入 Category 类cate = get_object_or_404(Category, pk=pk)post_list = Post.objects.filter(category=cate)#.order_by('-created_time')return render(request, 'blog/index.html', context={'post_list': post_list})

初步改写如下:

class CategoryView(ListView):model = Posttemplate_name = 'blog/index.html'context_object_name = 'post_list'def get_queryset(self):cate = get_object_or_404(Category, pk=self.kwargs.get('pk'))return super(CategoryView, self).get_queryset().filter(category=cate)

注意:

1)和 IndexView 不同的地方是,我们覆写了父类的 get_queryset 方法。该方法默认获取指定模型的全部列表数据,为了获取指定分类下的文章列表数据,我们覆写该方法,通过filter改变它的默认行为。

2)在类视图中,从 URL 捕获的路径参数值保存在实例的 kwargs 属性(是一个字典)里,非路径参数值保存在实例的 args 属性(是一个列表)里。

3)所以我们使了 self.kwargs.get(‘pk’) 来获取从 URL 捕获的分类 id 值。然后调用父类的 get_queryset 方法获得全部文章列表,紧接着就对返回的结果调用了 filter 方法来筛选该分类下的全部文章并返回。

4)此外我们可以看到 CategoryView 类中指定的属性值和 IndexView 中是一模一样的,所以如果为了进一步节省代码,甚至可以直接继承 IndexView。

优化后如下:

class CategoryView(IndexView):def get_queryset(self):cate = get_object_or_404(Category, pk=self.kwargs.get('pk'))return super(CategoryView, self).get_queryset().filter(category=cate)

接下俩,在 URL 配置中把 category 视图替换成类视图 CategoryView:

文件位置:blog/urls.py

app_name = 'blog'
urlpatterns = [...path('categories/<int:pk>/', views.CategoryView.as_view(), name='category'),
]

4.将 archive 视图函数改写成类视图

文件位置:blog/views.py

原视图函数如下:

def archive(request, year, month):"""定义 归档 视图"""post_list = Post.objects.filter(created_time__year=year,created_time__month=month)#.order_by('-created_time')return render(request, 'blog/index.html', context={'post_list': post_list})

改写如下:

 class ArchiveView(IndexView):def get_queryset(self):year = self.kwargs.get('year')month = self.kwargs.get('month')return super().get_queryset().filter(created_time__year=year, created_time__month=month)

接下俩,在 URL 配置中把 archive 视图替换成类视图 ArchiveView:

文件位置:blog/urls.py

app_name = 'blog'
urlpatterns = [...path('archives/<int:year>/<int:month>/', views.ArchiveView.as_view(), name='archive'),
]

5.将 tag 视图函数改写成类视图

文件位置:blog/views.py

原视图函数如下:

def tag(request, pk):# 记得在开始部分导入 Tag 类t = get_object_or_404(Tag, pk=pk)post_list = Post.objects.filter(tags=t)#.order_by('-created_time')return render(request, 'blog/index.html', context={'post_list': post_list})

改写如下:

 class TagView(IndexView):def get_queryset(self):t = get_object_or_404(Tag, pk=self.kwargs.get('pk'))return super().get_queryset().filter(tags=t)

接下俩,在 URL 配置中把 tag 视图替换成类视图 TagView:

文件位置:blog/urls.py

app_name = 'blog'
urlpatterns = [...path('tags/<int:pk>/', views.TagView.as_view(), name='tag'),
]

6.DetailView

除了从数据库中获取模型列表的数据外,从数据库获取模型的一条记录数据也是常见的需求。

比如查看某篇文章的详情,就是从数据库中获取这篇文章的记录然后渲染模板。

对于这种类型的需求,django 提供了一个 DetailView 类视图。

7.将DetailView视图函数改写成类视图

接下俩,将 detail 视图函数转换为等价的类视图 PostDetailView视图

文件位置:blog/views.py

原视图函数如下:

def detail(request, pk):"""定义文章详情页视图"""post = get_object_or_404(Post, pk=pk)#阅读量+1post.increase_views()md = markdown.Markdown(extensions=['markdown.extensions.extra','markdown.extensions.codehilite',# 'markdown.extensions.toc',# 记得在顶部引入 TocExtension 和 slugifyTocExtension(slugify=slugify),])post.body = md.convert(post.body)m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S)post.toc = m.group(1) if m is not None else ''return render(request, 'blog/detail.html', context={'post': post})

改写如下:

class PostDetailView(DetailView):model = Posttemplate_name = 'blog/detail.html'context_object_name = 'post'def get(self, request, *args, **kwargs):# 覆写 get 方法的目的是因为每当文章被访问一次,就得将文章阅读量 +1# get 方法返回的是一个 HttpResponse 实例# 之所以需要先调用父类的 get 方法,是因为只有当 get 方法被调用后,# 才有 self.object 属性,其值为 Post 模型实例,即被访问的文章 postresponse = super().get(request, *args, **kwargs)# 将文章阅读量 +1# 注意 self.object 的值就是被访问的文章 postself.object.increase_views()# 视图必须返回一个 HttpResponse 对象return responsedef get_object(self, queryset=None):# 覆写 get_object 方法的目的是因为需要对 post 的 body 值进行渲染post = super().get_object(queryset=None)md = markdown.Markdown(extensions=['markdown.extensions.extra','markdown.extensions.codehilite',# 记得在顶部引入 TocExtension 和 slugifyTocExtension(slugify=slugify),])post.body = md.convert(post.body)m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S)post.toc = m.group(1) if m is not None else ''return post

注意:

1)首先我们为 PostDetailView 类指定了一些属性的值,这些属性的含义和 ListView 中一样。

2)紧接着我们覆写了 get 方法。这对应着 detail 视图函数中将 post 的阅读量 +1 的那部分代码。事实上,你可以简单地把 get 方法的调用看成是 detail 视图函数的调用。

3)接着我们又复写了 get_object 方法。对应着 detail 视图函数中根据文章的 id(也就是 pk)获取文章,然后对文章的 post.body 进行 Markdown 解析。

4)get 方法看成是 detail 视图函数,至于其它的像 get_object、get_context_data 都是辅助方法,这些方法最终在 get 方法中被调用,这里你没有看到被调用的原因是它们隐含在了 super(PostDetailView, self).get(request, *args, **kwargs) 即父类 get 方法的调用中。最终传递给浏览器的 HTTP 响应就是 get 方法返回的 HttpResponse 对象。

接下俩,在 URL 配置中把 detail 视图替换成类视图 PostDetailView:

文件位置:blog/urls.py

app_name = 'blog'
urlpatterns = [...path('posts/<int:pk>', views.PostDetailView.as_view(), name = 'detail'),
]

Diango博客--13.将“视图函数”类转化为“类视图”相关推荐

  1. Diango博客--15.通过 Django Pagination 实现简单分页(一)

    文章目录 0.思路引导 1.Paginator 类的常用方法 2.用 Paginator 给文章列表分页 3.在模板中设置分页导航 4.效果展示 0.思路引导 1)当博客上发布的文章越来越多时,通常需 ...

  2. Diango博客--1.Django的接客之道

    文章目录 0.思路引导 1.实现最简单的HelloWorld 2.实现最简单的HelloWorld(使用Templates) 0.思路引导 django 的开发流程: 即首先配置 URL,把 URL ...

  3. Diango博客--22.Django Haystack 全文检索与关键词高亮

    文章目录 1. Django Haystack 简介 2. 安装 django-haystack和elasticsearch 2 3. 构建容器来运行 elasticsearch 服务 4. 配置 H ...

  4. Diango博客--8.解锁博客侧栏

    文章目录 0.思路引导 1.[最新文章] 模板标签 2.[归档] 模板标签 3.[分类] 模板标签 4.[标签云] 模板标签 5.使用自定义的模板标签 0.思路引导 博客侧边栏有四项内容:最新文章.归 ...

  5. 用 Flask 来写个轻博客 (13) — M(V)C_WTForms 服务端表单检验

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 WTForms WTF 的基础使用 常用的字段类型 fields.Da ...

  6. Diango博客--23.单元测试:测试 blog 应用

    文章目录 1. 前言 2. 搭建测试环境 3. 测试模型 4. 测试视图 5. 测试模板标签 6. 测试辅助方法和类 1. 前言 我们博客功能越来越来完善了,但这也带来了一个问题,我们不敢轻易地修改已 ...

  7. Diango博客--20.开启 Django 博客的 RSS 功能

    1.Rss简介 博客提供 RSS 订阅应该是标配,这样读者就可以通过一些聚合阅读工具订阅你的博客,时时查看是否有文章更新,而不必每次都跳转到博客上来查看.现在我们就来为博客添加 RSS 订阅功能. R ...

  8. Diango博客--10.交流的桥梁“评论功能”

    文章目录 0.思路引导 1.创建"评论"应用 2.设计"评论"的数据库模型 3.注册"评论"模型到 admin 4.设计"评论&q ...

  9. Diango博客--21.实现简单的全文搜索

    文章目录 1. 概述 2. 模板:将关键词提交给服务器 3. 视图:查找含有搜索关键词的文章 4. 视图:绑定 URL 1. 概述 搜索是一个复杂的功能,但对于一些简单的搜索任务,我们可以使用 Dja ...

最新文章

  1. 对AFNetworking的简单封装
  2. ubuntu16.04安装torch
  3. MySQL5.6 主从复制配置
  4. 引用js/css时,加入时间戳解决浏览器缓存问题
  5. xwpftemplate的时间设置_数据导出生成word附件使用POI的XWPFTemplate对象
  6. csc.exe的使用
  7. centOS7安装node+mongoDB+redis+express(forerver)+nginx+https
  8. H5网站接入微信支付(H5支付+JSAPI支付)
  9. Ubuntu各版本代号
  10. 用Python把20年的GDP、人口以及房价数据进行了可视化
  11. Jmeter的元件使用介绍:前置处理器详解
  12. c语言 求矩阵各行元素之和
  13. 数字人民币试点目前呈现“全面开花”态势
  14. Arthas开源一周年,Github Star 160K,我们一直在坚持什么?
  15. (ICLR-2019)DARTS:可微分架构搜索
  16. 高等数学:第四章 不定积分(1)不定积分的概念与性质 换元积分法
  17. 电脑遥控接收器电路_遥控电路图讲解
  18. sdk版本对手机运行有什么影响 android,Android sdk版本以及兼容性问题
  19. 【更新】绝地求生超火分屏雷达手机IPAD电脑教程
  20. C语言 有a个学生,每个学生有b门课程的成绩。输入学生的序号后输出对应的全部成绩

热门文章

  1. java 1000以内的完数
  2. 男人七个健康“保鲜剂”
  3. 广州驾校考试实际道路考试注意事项(图)
  4. 读人、看人、做人(图)
  5. 100个经典的C语言算法
  6. 视频领域的Instagram:Viddy用户突破2600万
  7. 使用FFMPEG SDK解码流数据获得YUV数据及其大小
  8. springCloud - 第6篇 - 网关的实现:ZUUL
  9. VScode 格式化代码快捷键、修改快捷键
  10. 设置 shell 脚本中 echo 显示内容带颜色