Django学习笔记之Class-Based-View
Django写的多了,有些问题才逐渐认识到。
比如有一个view比较复杂,调用了很多其他的函数。想要把这些函数封装起来,怎么办?
当然,可以用注释#------view------这样将函数隔离开,这种方法太low了,简直是在骗自己,连封装都算不上。
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。
所以Django在后来加入了Class-Based-View。可以让我们用类写View。
这样做的优点主要下面两种:
(1)提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承);
(2)可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性;
要理解django的class-based-view(以下简称cbv),首先要明白django引入cbv的目的是什么。在django1.3之前,generic view也就是所谓的通用视图,使用的是function-based-view(fbv),亦即基于函数的视图。有人认为fbv比cbv更pythonic,但是,python的一大重要的特性就是面向对象。而cbv更能体现python的面向对象。cbv是通过class的方式来实现视图方法的。class相对于function,更能利用多态的特定,因此更容易从宏观层面上将项目内的比较通用的功能抽象出来。 cbv的实现原理通过看django的源码就很容易明白,大体就是由url路由到这个cbv之后,通过cbv内部的dispatch方法进行分发,将get请求分发给cbv.get方法处理,将post请求分发给cbv.post方法处理,其他方法类似。并且,cbv里引入了mixin的概念。Mixin就是写好了的一些基础类,然后通过不同的Mixin组合成为最终想要的类。
所以,理解cbv的基础是,理解Mixin。Django中使用Mixin来重用代码,一个View Class可以继承多个Mixin,但是只能继承一个View(包括View的子类),推荐把View写在最右边,多个Mixin写在左边。Mixin也是比较复杂的技术 。
如何正确使用 CBVs (Class-based views)
1. CBVs的使用原则
- 代码越少越好
- 永远不要重复代码
- View应当只包含呈现逻辑, 不应包括业务逻辑
- 保持view逻辑清晰简单
- 不要将CBVs用作403, 404, 500的错误处理程序
- 保持mixin简单明了
2. 如何使用mixin
在编程中mixin是指为继承它的class提供额外的功能, 但它自身却不能单独使用的类. 在具有多继承能力的编程语言中, mixin可以为类增加额外功能或方法. 在Django中, 我们可以使用mixin为CBVs提供更多的扩展性, 当然在类继承过程中, 我们推荐以下原则:
- Django自身提供的View永远在最右边
- mixin依次在以上view的左边
- mixin永远继承自Python的object类型
在这里顺便推荐一个很好的django库: django-braces. 该库中提供众多django的mixin, 可以方便我们日常使用.
以下是一个简单地例子, TemplateView是django自身提供的基本View, 因此在最右边; FreshFruitMixin则在TemplateView左边; FreshFruitmixin继承自object:
- from django.views.generic import TemplateView
- class FreshFruitMixin(object):
- def get_context_data(self, **kwargs):
- context = super(FreshFruitMixin, self).get_context_data(**kwargs)
- context["has_fresh_fruit"] = True
- return context
- class FruitFlavorView(FreshFruitMixin, TemplateView):
- template_name = "fruit_flavor.html"
3. 如何使用Django自身的CBV
CBVs在功能上的可扩展性, 牺牲的是简单性, 一个CBV最多的时候拥有8个import关系. (如果希望进一步了解这些继承关系, 可以使用Classy Class-Based Views进行查看.) 所以要弄懂那个View最适合当下的场景对于开发人员也是一个挑战. 为了减少CBVs的使用难度, 我们将这些View和基本的用法列在下表中, 为了显示方便, 名字前的django.views.generic前缀皆省去:
名字 | 目的 | 例子 |
---|---|---|
View | 基本View, 可以在任何时候使用 | 见后面详细介绍 |
RedirectView | 重新定向到其他URL | 将访问"/log-in/"的用户重新定向到"/login/" |
TemplateView | 显示Django HTML template | 一般网站中使用模板显示的页 |
ListView | 显示对象列表 | 文章列表页 |
DetailView | 显示对象详情 | 文章详细页 |
FormView | 提交From | 网站联系我们或emai订阅form |
CreateView | 创建对象 | 创建新文章页 |
UpdateView | 更新对象 | 修改文章页 |
DeleteView | 删除对象 | 删除文章页 |
Generic date views | 显示一段时间内的对象 | 按时间归类的博客 |
4. CBVs的使用技巧
a. 限定访问权限
在django tutorial中介绍了如何一起使用django.contrib.auth.decorators.login_required和CBV, 这是一个典型的错误例子.
还好, 我们有django-braces. 在django-braces中已经提供了一个LoginRequiredMixin:
- # myapp/views.py
- from django.views.generic import DetailView
- from braces.views import LoginRequiredMixin
- from .models import Article
- class ArticleDetailView(LoginRequiredMixin, DetailView):
- model = Article
b. 在form提交成功后执行代码
当需要在form提交成功后执行自定义的代码时, 可以使用form_valid()方法, form_valid()方法返回的是django.http.HttpResponseRedirect:
- # myapp/views.py
- from django.views.generic import CreateView
- from braces.views import LoginRequiredMixin
- from .models import Article
- class ArticleCreateView(LoginRequiredMixin, CreateView):
- model = Article
- fields = ('title', 'slug', 'content')
- def form_valid(self, form):
- # 自定义的代码逻辑写在这里
- return super(ArticleCreateView, self).form_valid(form)
c. 在form提交不成功后执行代码
当需要在form提交不成功后执行自定义的代码时, 可以使用form_invalid()方法, form_invalid()方法返回的也是django.http.HttpResponseRedirect:
- # myapp/views.py
- from django.views.generic import CreateView
- from braces.views import LoginRequiredMixin
- from .models import Article
- class ArticleCreateView(LoginRequiredMixin, CreateView):
- model = Article
- def form_invalid(self, form):
- # 自定义的代码逻辑写在这里
- return super(ArticleCreateView, self).form_invalid(form)
5. CBV和form如何结合使用
下面我们介绍一下常见的django form和CBV结合使用的模式, 首先我们定义一个Article model方便举例:
- # myapp/models.py
- from django.db import models
- from django.core.urlresolvers import reverse
- STATUS = {
- (0, 'zero'),
- (1, 'one'),
- }
- class Article(models.Model):
- title = model.CharField(max_length=255)
- slug = model.SlugField()
- review_num = models.IntegerField(default=0, choices=STATUS)
- def get_absolute_url(self):
- return reverse("article_detail", kwargs={"slug": self.slug})
a. Views和ModelForm
下面的例子中, 我们利用django.contrib.messages和CBVs构建一套创建, 更新和显示一篇article的view, 包括:
- ArticleCreateView: 用于创建新article
- ArticleUpdateView: 用于更新article
- ArticleDetailView: 用于确认创建或更新后的article
- # myapp/views.py
- from django.contrib import messages
- from django.views.generic import CreateView, UpdateView, DetailView
- from braces.views import LoginRequiredMixin
- from .models import Article
- class ArticleActionMixin(object):
- @property
- def success_msg(self):
- return NotImplemented
- def form_valid(self, form):
- messages.info(self.request, self.success_msg)
- return super(ArticleActionMixin, self).form_valid(form)
- class ArticleCreateView(LoginRequiredMixin, ArticleActionMixin, CreateView):
- model = Article
- fields = ('title', 'slug', 'review_num')
- success_msg = "Article Created!"
- class ArticleUpdateView(LoginRequiredMixin, ArticleActionMixin, UpdateView):
- model = Article
- fields = ('title', 'slug', 'review_num')
- success_msg = "Article Updated!"
- class ArticleDetailView(DetailView):
- model = Article
接下来是template
- {# templates/myapp/article_detail.html #}
- {% if messages %}
- <ul class="messages">
- {% for message in messages %}
- <li>{ message } </li>
- </ul>
- {% endif %}
b. Views和Form
下面我们以搜索article功能为例子, 介绍一下CBV和form的常见使用样式, 在article列表页中点击搜索按钮, 显示搜友符合条件的article列表:
- # myapp/views.py
- from django.views.generic import ListView
- from .models import Article
- class ArticleListView(ListView):
- model = Article
- def get_queryset(self):
- queryset = super(ArticleListView, self).get_queryset()
- q = self.request.GET.get('q')
- if q:
- return queryset.filter(title__icontains=q)
- return queryset
然后可以使用include以下tenplate呈现搜索form:
- {# templates/myapp/_article_search.html #}
- <form action="{% url "article_list" %} method="GET"">
- <input type="text" name="q"></>
- <button type="submit">搜索</>
- </form>
6. 单独使用View
只用django.views.generic.View, 而不用FBV来构建所有django项目中的view也是可行的, 这也没有你所想象的那么复杂. 使用View的好处是, 我们不需要写许多内套式的if语句, 我们可以直接覆盖使用View的get(), post()等方法:
- from django.shortcuts import get_object_or_404, render, redirect
- from django.views.generic import View
- from braces.views import LoginRequiredMixin
- from .forms import ArticleForm
- from .models import Article
- class ArticleView(LoginRequiredMixin, View):
- def get(self, request, *args, **kwargs):
- article = get_object_or_404(Article, pl=kwargs['slug'])
- return render(request,
- "myapp/article_detail.html",
- {"article": article}
- )
- def post(sele, request, *args, **kwargs):
- article = get_object_or_404(Article, pl=kwargs['slug'])
- form = ArticleForm(request.POST)
- if form.is_valid():
- form.save()
- return redirect("myapp:article", article.slug)
Django学习笔记之Class-Based-View的更多相关文章
- Django学习笔记(五)—— 表单
疯狂的暑假学习之 Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path ...
- Django学习笔记(9)—— 开发用户注册与登录系统
一,项目题目: 开发用户注册与登录系统 该项目主要练习使用Django开发一个用户注册与登录的系统,通过这个项目然后巩固自己这段时间所学习的Django知识. 二,项目需求: 开发一个简单的用户登录与 ...
- Django学习笔记(4)——Django连接数据库
前言 在MVC或者MTV设计模式中,模型(M)代表对数据库的操作.那么如何操作数据库呢?本小节就认真学习一下.首先复习一下Django的整个实现流程 ,然后再实现一下使用数据库的整个流程,最后学习一下 ...
- Django学习笔记---第一天
Django学习笔记 1.Django的安装 //如果不指定版本号,默认安装最新版 pip3 install django==1.11.8 关于Django的版本和python的版本依赖关系,请看下图 ...
- Django学习笔记(13)——Django的用户认证(Auth)组件,视图层和QuerySet API
用户认证组件的学习 用户认证是通过取表单数据根数据库对应表存储的值做比对,比对成功就返回一个页面,不成功就重定向到登录页面.我们自己写的话当然也是可以的,只不过多写了几个视图,冗余代码多,当然我们也可 ...
- Django学习笔记(一)——安装,创建项目,配置
疯狂的暑假学习之 Django学习笔记(一) 教材 书<The Django Book> 视频:csvt Django视频 1.创建项目 django‐admin.py startpro ...
- Django学习笔记(18)——BBS+Blog项目开发(2)主体思路及流程
这篇博客主要完成一个BBS+Blog项目,那么主要是模仿博客园的博客思路,使用Django框架进行练习. 准备:项目需求分析 在做一个项目的时候,我们首先做的就是谈清楚项目需求,功能需求,然后才开始写 ...
- Django学习笔记(16)——扩展Django自带User模型,实现用户注册与登录
一,项目题目:扩展Django自带User模型,实现用户注册与登录 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册,登录,用户认证,注销,修改密码等功能. ...
- Django学习笔记(14)——AJAX与Form组件知识补充(局部钩子和全局钩子详解)
我在之前做了一个关于AJAX和form组件的笔记,可以参考:Django学习笔记(8)——前后台数据交互实战(AJAX):Django学习笔记(6)——Form表单 我觉得自己在写Django笔记(8 ...
- Django学习笔记(11)——开发图书管理页面
一,项目题目: 开发图书管理页面 该项目主要练习Django对多个数据库进行增删改查的操作. 二,项目需求: 基础需求:75% 1. 列出图书列表.出版社列表.作者列表 2. 点击作者,会列出其出版的 ...
随机推荐
- centos7最小化安装后配置笔记
一.安装wget(步骤2备用) yum install wget -y 二.切换yum源为阿里云 备份旧源: mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum ...
- 每天一个linux命令(文件操作):【转载】whiereis命令
whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b).man说明文件(参数-m)和源代码文件(参数-s).如果省略参数,则返回所有信息. 和find相比,whereis查找的速度非 ...
- LOJ2359. 「NOIP2016」天天爱跑步【树上差分】
LINK 思路 首先发现如果对于一个节点,假设一个节点需要统计从字数内来的贡献 需要满足\(dep_u - dep_s = w_u\) 这个条件其实可以转化成\(dep_u - w_u = dep_s ...
- 开启opcache提高性能
在开启opcache之前,我们先介绍一下编译与解释: 编译器是把源程序的每一条语句都编译成机器语言,并保存成二进制文件,这样运行时计算机可以直接以机器语言来运行此程序,速度很快:而解释器则是只在执行程 ...
- javascript异常处理。 屏蔽异常
http://www.cnblogs.com/aqbyygyyga/archive/2011/10/29/2228824.html
- 【java基础】java中ArrayList,LinkedList
[一]ArrayList 一ArrayList的内部结构 (1)ArrayList内部维护的是一个Object数组 (2)ArrayList数组扩容后数组的长度的公式:旧的数组长度+(旧数组长度> ...
- 莫名其妙的js基础学习!
JavaScript基本组成部分: 1,ECMAScript:js的语法标准,基本的变量,运算符,函数,if语句,for语句等 2,DOM:操作网页上的元素API,比如盒子的移动,变色,轮播图等. 3 ...
- NGINX conf 配置文件中的变量大全 可用变量列表及说明
$args #这个变量等于请求行中的参数.$content_length #请求头中的Content-length字段.$content_type #请求头中的Content-Type字段.$docu ...
- 初学者手册-IDEA中的Git
1.Git的更新.提交.还原 IDEA中Git的更新.提交.还原方法 2.设置Git的提交方式为http 3.
- 性能监控之Spotlight
有和同事探讨一些技术监控类软件,谈到Spotlight,临时记一下. 下载地址https://pan.baidu.com/s/1HB9xd9LmOR-MOk8FIGBm-A 常规安装模式,下载解压安装 ...