本节内容

一   Class Based View 基于类的视图

  1.  类的视图 View

  2.  类的视图 TemplateView

  3.  类的视图 login_required解决方法

二  通用视图

  1.  通用视图 - ListView

  2.  通用视图 - DetailView

  3.  通用视图 - FormView

一  Class Based View 基于类的视图

function view 存在问题,无法继承复用,尤其时框架封装好的类用不了,function组装复用更擅长

class based view 代码更简洁

简单样例

version 1

# urls.py
from django.conf.urls import url
from mysite import views as my_view urlpatterns = [
url(r'^about/', my_view.about),
] # mysite/views.py
from django.shortcuts import render def about(request):
return render(request, 'about.html')

基本的function based view

version 2

# urls.py
from django.views.generic import TemplateView
urlpatterns = [
url(r'^about/', TemplateView.as_view(template_name='about.html')),
] # mysite/views.py
from django.shortcuts import render def about(request):
return render(request, 'about.html')

TemplateView.as_view(template_name='about.html'))  方法 as_view(),参数template_name=‘网页模板’

version 3

# mysite/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = 'about.html' #mysite/urls.py
from mysite import views as my_view urlpatterns = [
url(r'^about/', my_view.AboutView.as_view()),
]

说明:

  • as_view()返回的是一个function object

  • 模板名字作为as_view参数传进去,也可以作为类变量设置template_name = '网页模板'

1.  类的视图 View

# mysite/views.py
def my_view(request):
if request.method == 'GET':
return render(request, 'about.html')
elif request.method == 'POST':
return HttpResponse('post it')
elif request.method == 'HEAD':
return HttpResponse('head it')
# mysite/urls.py
from mysite import views
urlpatterns = [
url(r'^about/', views.my_view),
]

等价于 类图公共基类View

# mysite/views.py
from django.shortcuts import render,HttpResponse
from django.views.generic import View class MyView(View):
def get(self, request):
return render(request, 'about.html') def post(self, request):
return HttpResponse('post it') def head(self, request):
return HttpResponse('head it') # mysite/urls.py
from mysite import views as my_view
urlpatterns = [
url(r'^about/', my_view.MyView.as_view()),
]

类视图好处就是可以直接继承和覆盖

# mysite/views.py
from django.views.generic import View
class GreetingView(View):
greeting = 'Good Day'
def get(self, request):
return HttpResponse(self.greeting) class MorningGreeting(GreetingView):
greeting = 'Morning to ya' # mysite/urls.py
urlpatterns = [
my_view.GreetingView.as_view(greeting="G'day")),
]

源码分析

class View(object):
# 所有views的公共类,仅仅实现 dispatch方法和简单安全性验证 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs):
for key, value in six.iteritems(kwargs):
setattr(self, key, value) @classonlymethod
def as_view(cls, **initkwargs):
# request-response的主入口点 for key in initkwargs:
# 不能有get,post等方法名的参数,后续有setattr()操作,会覆盖原始请求方法
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__)) # 如果传入了一个没有定义的类属性,就报错;如有greeting属性,就不报错
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key)) # 定义了类似闭包的视图函数
def view(request, *args, **kwargs):
self = cls(**initkwargs) # 调用__init__()进行实例化
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs) # 调用 self.dispatch()进行处理 # 对view object设置了一些属性
view.view_class = cls
view.view_initkwargs = initkwargs # 更新文档说明
update_wrapper(view, cls, updated=()) # and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view def dispatch(self, request, *args, **kwargs):
# 将request.method反射到类相应的方法上,并执行
if request.method.lower() in self.http_method_names:
# 如果有如get,就handler=get;如果没有handler = self.http_method_not_allowed
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning(
'Method Not Allowed (%s): %s', request.method, request.path,
extra={'status_code': 405, 'request': request}
)
return http.HttpResponseNotAllowed(self._allowed_methods()) def options(self, request, *args, **kwargs):
"""
Handles responding to requests for the OPTIONS HTTP verb.
"""
response = http.HttpResponse()
response['Allow'] = ', '.join(self._allowed_methods())
response['Content-Length'] = ''
return response def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]

类View

#!/usr/bin/env python3
# -*-coding:utf-8 -*-
# __author__:Jonathan
# email:nining1314@gmail.com from django.shortcuts import HttpResponse
from django import http
from django.utils import six
from django.utils.decorators import classonlymethod
from django.conf.urls import url class View(object):
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs):
for key, value in six.iteritems(kwargs):
setattr(self, key, value) @classonlymethod
def as_view(cls, **initkwargs):
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("禁止 %s 作为 %s()关键字参数" % (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("类 %s() 接收到非法参数 %s,只接受类存在类属性" % (cls.__name__, key)) def view(request, *args, **kwargs):
# 把 as_view()传入的关键字参数,赋值为相应的类变量
self = cls(**initkwargs) # 类的实例化,虽然只是一行代码,要理解原理:是有很多行代码执行完的结果
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs) # 一行代码,代表的是self.dispatch()的执行结果 # 函数也是一种对象,可以有自己的属性****
view.view_class = cls
view.view_initkwargs = initkwargs # 返回闭合的函数对象
return view def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 一行代码,代表的是handler()的执行结果
"""最终dispatch结果:根据request.method.lower()得到相应的http请求方法,反射到同名类方法,执行""" def http_method_not_allowed(self, request, *args, **kwargs):
return http.HttpResponseNotAllowed(self._allowed_methods()) def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)] class MyView(View):
def get(self, request):
return HttpResponse('get it') def post(self, request):
return HttpResponse('post it') def head(self, request):
return HttpResponse('head it') urlpatterns = [
url(r'^my_view/', MyView.as_view()),
]

吃透类View

说明:

  • as_view返回一个 view function

  • as_view接收参数是可以覆盖类定义的变量

  • __init__检查as_view传入的参数是否在类中定义

  • View.as_view()返回函数视图的view 对象,说明类视图只是对原有的函数视图进行了封装,而没有否定函数view的作用

  • view function运行时会调用dispatch,根据用户的request.method路由到get, post等方法

最终得出结论:

View类 在没有更改原Django逻辑的情况下,可以用类来编写view,每个http请求会使用对应类的同名方法进行处理

2.  类的视图 TemplateView

class ContextMixin(object):
# 渲染模板时,处理需要的上下文参数 def get_context_data(self, **kwargs):
if 'view' not in kwargs:
kwargs['view'] = self
return kwargs class TemplateResponseMixin(object):
# 渲染模板,Mixin一般是小功能类封装,被其他类继承 template_name = None
template_engine = None
response_class = TemplateResponse
content_type = None def render_to_response(self, context, **response_kwargs):
# 进行模板渲染,render()是个函数,response_class()是个类,实现本质目标没多大区别 response_kwargs.setdefault('content_type', self.content_type)
return self.response_class(
request=self.request,
template=self.get_template_names(),
context=context,
using=self.template_engine,
**response_kwargs
) def get_template_names(self):
if self.template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of "
"'template_name' or an implementation of 'get_template_names()'")
else:
return [self.template_name] class TemplateView(TemplateResponseMixin, ContextMixin, View):
# 实现get()方法,有渲染上文参数,有渲染操作 def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)

类TemplateView

说明:

  • 每个Mixin只提供部分功能,最终需要类整合

  • TemplateResponseMixin提供render_to_response() 方法,渲染模板

  • ContentMixin提供get_context_data()方法,提供渲染数据

  • View提供get,post用户访问接口

  • 面向对象编程:如何拆分功能模块,如何组装功能模块

3.  类的视图 login_required解决方法

3.1  封装Mixin(推荐)

from django.contrib.auth.decorators import login_required

class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **initkwargs):
view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
return login_required(view) class MyView(LoginRequiredMixin, ...):
pass

3.2 装饰类

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView class ProtectedView(TemplateView):
template_name = 'secret.html' @method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)

推荐学习网站:http://devdocs.io/

二  通用视图

通用视图(generic class base view) 和 class base view 概念上不是一回事

Class Base View 是指用类的方式去写视图

通用视图 是用Class Base View的方式将我们常用的增、删、改、查封装成可扩展的类,使用时直接继承、快速实现

1.  通用视图 - ListView

配置编程,获取数据列表

from django.db import models

class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField() def __str__(self):
return self.name class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField() def __str__(self):
return '%s %s' % (self.first_name, self.last_name) class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField('Author')
publisher = models.ForeignKey('Publisher')
publication_date = models.DateField(auto_now_add=True) def __str__(self):
return self.title

models.py

from django.views.generic import ListView
from .models import Publisher class PublisherList(ListView):
model = Publisher # 类属性:指定解析的model
# queryset = Publisher.objects.all()[0:1] # 和model二选一,获取指定数据
context_object_name = 'publishers' # 默认object_list,前端渲染时的上下文参数
# template_name = 'books/publisher_list.html' # 指定渲染的模板文件,默认值model名小写_list.html # 联系类的queryset,而该方法为实例的定制
def get_queryset(self):
print(self.request) # 根据 self.request进行判断,返回符合条件的queryset
return Publisher.objects.all()[0:1]
urlpatterns = [
url(r'^publishers/$', views.PublisherList.as_view(), name='publishers'),
]

说明:

  • multi object list view

  • model、queryset和get_queryset三者之间关系

  • content_object_name

  • template_name

源码UML图分析:

2.  通用视图 - DetailView

显示一个object的详情页面

from django.views.generic import DetailView
from .models import Publisher
from .models import Book class PublisherDetail(DetailView):
model = Publisher
context_object_name = 'publisher' # 模板渲染对象,默认值object def get_context_data(self, **kwargs):
context = super(PublisherDetail, self).get_context_data(**kwargs)
context['book_list'] = Book.objects.all() # 附加额外选软数据
return context '''
# 默认的object,是从url里的pk获取的
def get_object(self, queryset=None):
object = super(PublisherDetail, self).get_object()
# 进行更新操作
# object.last_accessed = timezone.now()
# object.save()
return object
'''
urlpatterns = [
url(r'^publisher/(?P<pk>[0-9]+)/$', views.PublisherDetail.as_view(), name='publisher-detail'),
]

说明:

  • Single object detail view

  • get_context_data

  • content_object_name

  • get_object

源码UML图分析:

3.  通用视图 - FormView

  • FormView

  • CreateView,UpdateView,DeleteView

Django Class Based View的更多相关文章

  1. Django Function Based View(FBV)和Class Based View (CBV)对比

    一.FBV处理过程 首先来看一下FBV逻辑过程: 1.简单过程(借用官方示例): urls: from django.conf.urls import url from . import views ...

  2. Django 类方式view进行进行用户验证

    问题: Django中,view的书写方式有两种,一种是def函数方式,一种是class方式,函数方式通过@login_required装饰器标记函数,就必须通过用户验证,而类,则没办法通过此方法进行 ...

  3. Django 基础二(View和urls)

    上一篇博文已经成功安装了python环境和Django,并且新建了一个空的项目.接下来就可以正式开始进行Django下 的Web开发了.首先进入项目的主目录: cd ./DjangoLearn/hol ...

  4. Django中的View视图讲解

    Django中的View视图(view.py)是负责处理用户请求和返回响应的逻辑. 视图函数或视图简而言之就是一个python函数,它接受一个web请求并返回一个Web响应. 此响应可以是网页的HTM ...

  5. python3开发进阶-Django视图(View)的常见用法

    阅读目录 简述Django的View(视图) CBV和FBV Request对象和Response对象 Django组件(render,redirect)详解 一.简述Django的View(视图) ...

  6. Django框架 之 view视图

    Django框架 之 view视图 浏览目录 概述 简单的视图 HttpRequest对象 CBV和FBV 给视图加装饰器 Request对象 Response对象 JsonResponse对象 Dj ...

  7. Django Restful API Class Based View

    基于class定义view 前言: 我们首先通过以class的方式重写view,我们可以自己构造类也可以通过res_framework 提供的mixins和generics类库直接构造类 下面来看下自 ...

  8. Django views 中 View decorators

    decorators(装饰器) 1. require_http_methods 在django.views.decorators.http中,可以用来限制请求的权限. require_http_met ...

  9. Django App(三) View+Template

    接着上一节(二)的内容,首先启动站点,通过界面添加Question和Choice两张表的数据,因为接下来,要向polls app里面添加views. 1.添加数据如下(这里是通过界面操作添加的数据) ...

随机推荐

  1. Java 虚拟机面试题全面解析(干货)

    Java 虚拟机面试题全面解析(干货) JDK 是什么 JRE 是什么 Java历史版本的特性 Java Version SE 50 Java Version SE 6 Java Version SE ...

  2. C++学习基础十六-- 函数学习笔记

    C++ Primer 第七章-函数学习笔记 一步一个脚印.循序渐进的学习. 一.参数传递 每次调用函数时,都会重新创建函数所有的形参,此时所传递的实参将会初始化对应的形参. 「如果形参是非引用类型,则 ...

  3. Jenkins部署报weblogic.deploy.api.tools.deployer.DeployerException: Java heap space

    Jenkins部署报weblogic.deploy.api.tools.deployer.DeployerException: Java heap space异常 解决办法: 在MAVEN_OPTS中 ...

  4. 2D射影空间,为何引入射影空间

    2D欧氏空间R2中,点的表示是A(x1,y1), B(x2,y2),二维参数,线的表示是L: y=kx+b,是二维参数: 如何表示点在线上面?可以扩展为(k,-1,b)* (x1,y1,1)t = 0 ...

  5. 在windows下安装Git并用GitHub同步

    准备环境: 1,注册github账户 2,下载安装git(下载地址:https://git-scm.com/download/win) 注释: git是什么? git是版本管理工具,当然也是分布式的管 ...

  6. 简化Getter 与 Setter 的插件 Lombok

    参考文档:https://www.jianshu.com/p/365ea41b3573 第一步:添加依赖 <dependency> <groupId>org.projectlo ...

  7. 字符串的排列(python)

    题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输 ...

  8. Python类继承(转发)

    目录 一.概述 二.类的继承 2.1 继承的定义 2.2 构造函数的继承 2.3 子类对父类方法的重写 三.类继承的事例 回到顶部 一.概述 面向对象编程 (OOP) 语言的一个主要功能就是“继承”. ...

  9. 天天向上的力量 III

    描述 一年365天,以第1天的能力值为基数,记为1.0. 当好好学习时,能力值相比前一天提高N‰:当没有学习时,能力值相比前一天下降N‰. 每天努力或放任,一年下来的能力值相差多少呢?其中,N的取值范 ...

  10. js+正则+单双引号问题

    在处理用js动态添加表格时,表格中有正则表达式,其单双引号问题导致的添加表格不成功,和正则失效问题 <script type="text/javascript"> va ...