首页 > 其他 > 详细

Django开发博客系统(10-使用class-based view)

时间:2020-04-03 19:53:05      阅读:76      评论:0      收藏:0      [点我收藏+]

类的继承让代码的复用变得容易,当我们代码的逻辑被重复使用,同时有需要共享的数据,就可以考虑封装一个类来使用.

Django提供了下面几个class-based view

l  View: 基础的View,实现了基于HTTP方法得分发(dispatch)逻辑,比如GET请求会调用对应的get方法,POST请求会调用对应的post方法,但它自己没有实现具体的get或者post方法.

l  TemplateView: 继承自View,可以直接用来返回指定的模板.它实现了get方法,可以传递变量到模板中来进行数据展示.

l  DetailView: 继承自View,实现了get方法,并且可以绑定某一个模板,用来获取单个实例的数据.

l  ListView:继承自View,实现了get方法,可以通过绑定模板来批量获取数据

 

下面通过代码来实际体验一下.

View:

class MyView(View):
    def get(self, request):
        return HttpResponse(result)

urls.py

1 path(view/, views.MyView.as_view()),

 

这样写相当于:

1 def my_view(request):
2     if request.method == GET:
3         return HttpResponse(result)

使用class-based view来实现的一个明显的好处就是解耦了HTTP的各种请求,在这种情况下,如果我们如果需要给视图新增一个处理POST请求的逻辑,不需要再去修改get函数,只需要新增一个post函数即可,无需去改变已有的逻辑.

而在路由配置中,通过as_view()来接收请求以及返回响应.这个函数会动态获取当前请求HTTP Method对应的方法来处理对应请求,简单理解就是做了if request.method == ‘‘判断并执行对应的操作.

 

TemplateView

增加了指定模板的功能,可以用来返回某个模板,也可以直接写到URL,这样返回的是静态页面

也可以继承TemplateView实现get_context_data方法来将要展示的数据传递到模板中.

简单的用法:

1 path(view/, TemplateView.as_view(template_name=view.html))

实现get_context_data:

1 def get_context_data(self, **kwargs):
2     context = super().get_context_data(**kwargs)
3     context.update({
4         sidebars: SideBar.get_all(),
5     })
6     context.update(Category.get_navs())
7 
8     return context

 

DetailView

DetailView可以理解为也拥有TemplateView的能力,并且可以通过绑定一个模板来指定数据源.

DetailView提供了如下属性和接口

l  model属性: 指定当前View要使用的Model

l  queryset属性:model一样,二选一.设定基础的数据集,model的设定没有过滤的功能,而通过queryset = Post.objects.filter()可以过滤.

l  template_name属性:模板名称

l  get_queryset接口:用来获取数据,如果设定了queryset则直接返回queryset

l  get_object接口:根据URL参数,queryset上获取对应的实例

l  get_context_data接口:获取渲染到模板中的所有上下文,如果有新增数据需要传递,可以重写该方法来实现.

PostDetailView来举例

1 class PostDetailView(DetailView):
2     queryset = Post.latest_posts()
3     template_name = detail.html
4     context_object_name = post
5     pk_url_kwarg = post_id

这里的pk_url_kwarg是用于接收一个来自url的参数,这个参数将作为查询条件

urls.py

1 path(post/<int:post_id>.html, views.PostDetailView.as_view(), name=post-detail),

 

ListView:

DetailView类似,不过DetailView只获取一条数据,ListView获取多条数据.因为是列表数据,如果数据类过大的话就没法一次都返回,因此还需要完成分页功能.

1 class IndexView(CommonViewMixin, ListView):
2     queryset = Post.latest_posts()
3     paginate_by = 1
4     context_object_name = post_lists
5     template_name = list.html

list.html

 

 1 {% extends ‘base.html‘ %}
 2 
 3 {% block title %}
 4     {% if tag %}
 5         标签页: {{ tag.name }}
 6     {% elif category %}
 7         分类页: {{ category.name }}
 8     {% else %}
 9         Posts
10     {% endif %}
11 {% endblock %}
12 
13 {% block main %}
14     <ul>
15         {% for post in post_lists %}
16             <li>
17                 <a href="{% url ‘blog:post-detail‘ post.id %}">{{ post.title }}</a>
18                 <div>
19                     <span>作者:{{ post.owner.username }}</span>
20                     <span>分类:{{ post.category.name }}</span>
21                 </div>
22                 <p>{{ post.desc }}</p>
23             </li>
24         {% endfor %}
25     </ul>
26     {% if page_obj %}
27         {% if page_obj.has_previous %}
28             <a href="?page={{ page_obj.previous_page_number }}">上一页</a>
29         {% endif %}
30         Page {{ page_obj.number }} of {{ paginator.num_pages }}.
31         {% if page_obj.has_next %}
32             <a href="?page={{ page_obj.next_page_number }}">下一页</a>
33         {% endif %}
34     {% endif %}
35 {% endblock %}

重构代码:

既然尝试了使用class-based view,那么接下来就把项目中的function view重构一下吧.views.py,我们写了post_listpost_detail两个视图函数

 

post_list,我们处理了多个URL的逻辑,如果使用class-based view的话,可以使用继承来复用代码,将他们拆开.

对于post_list中的所有模板,都会显示分类导航,侧边栏和底部导航,所以我们把这些数据定义为基类来进行代码复用.

CommonViewMixin:

1 class CommonViewMixin:
2     def get_context_data(self, **kwargs):
3         context = super().get_context_data(**kwargs)
4         context.update({
5             sidebars: SideBar.get_all(),
6         })
7         context.update(Category.get_navs())
8 
9         return context

这里其实就是把侧边栏和导航的数据传给了模板.

接着是首页的代码

IndexView:

1 class IndexView(CommonViewMixin, ListView):
2     queryset = Post.latest_posts()
3     paginate_by = 5
4     context_object_name = post_lists
5     template_name = list.html

 

CategoryView:

 1 class CategoryView(IndexView):
 2     def get_context_data(self, **kwargs):
 3         context = super(CategoryView, self).get_context_data(**kwargs)
 4         category_id = self.kwargs.get(category_id)
 5         category = get_object_or_404(Category, pk=category_id)
 6         context.update({
 7             category: category,
 8         })
 9 
10         return context
11 
12     def get_queryset(self):
13         queryset = super(CategoryView, self).get_queryset()
14         category_id = self.kwargs.get(category_id)
15 
16         return queryset.filter(category_id=category_id)

 

TagView:

 1 class TagView(IndexView):
 2     def get_context_data(self, **kwargs):
 3         context = super(TagView, self).get_context_data(**kwargs)
 4         tag_id = self.kwargs.get(tag_id)
 5         tag = get_object_or_404(Tag, pk=tag_id)
 6         context.update({
 7             tag: tag,
 8         })
 9 
10         return context
11 
12     def get_queryset(self):
13         queryset = super(TagView, self).get_queryset()
14         tag_id = self.kwargs.get(tag_id)
15 
16         return queryset.filter(tag_id=tag_id)

 

self.kwags就是我们URL中的参数的集合.

get_object_or_404,顾名思义,获取到则返回实例对象,不存在就抛出404错误.

博文详情页

1 class PostDetailView(CommonViewMixin, DetailView):
2     queryset = Post.latest_posts()
3     template_name = detail.html
4     context_object_name = post
5     pk_url_kwarg = post_id

路由配置

1 urlpatterns = [
2     path(category/<int:category_id>/, views.CategoryView.as_view(), name=category-list),
3     path(tag/<int:tag_id>/, views.TagView.as_view(), name=tag-list),
4     path(post/<int:post_id>.html, views.PostDetailView.as_view(), name=post-detail),
5     path(‘‘, views.IndexView.as_view(), name=post_list),
6 ]

自此我们的function view 就重构为class-based view,这里介绍一下ListViewGET流程,其他的View大同小异

1.      调用dispatch进行分发

2.      调用get方法

a)      首先调用get_queryset方法拿到数据源

b)     接着调用get_context_data方法,拿到需要渲染的模板中的数据

                 i.          首先调用get_paginate_by拿到每页的数据

               ii.          接着调用get_context_object_name拿到要渲染到模板中的这个queryset名称

              iii.          然后调用paginate_queryset进行分页处理

              iv.          最后拿到的数据转为dict并返回

c)      调用render_to_response渲染数据到页面中

                 i.          render_to_response中调用get_tempalte_names拿到模板名

               ii.          request,context,template_name等传到模板中

 

接下来要进行页面的一些渲染,毕竟数据是拿到了,页面太丑了也不会有人看=.=

另外就是渲染部分我可能到时候做好直接贴代码上来了,因为前端是真的不知道该怎么说= =

 

Django开发博客系统(10-使用class-based view)

原文:https://www.cnblogs.com/ylnx-tl/p/12628553.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!