转: django class base view 简单说明

这节我们讲一下Class-based View,为什么要有这个Class-based View呢?view不都是一个方法吗?跟类有啥关系?其实答案很明显,用类其实是为了抽象,抽象出通用的,将可变的暴露出来,这样我们就可以用最少的代码实现复杂的功能了。

Django中,对那些我们平时经常用的View进行了封装,比如用于渲染一个template的TemplateView,用于处理重定向的RedirectView,用于处理表单的FormView,用于处理数据库对象的DetailView和ListView等,这些View有一个共同的父类:View,在这个View类中,向外暴露了一个类方法:as_view(),它返回一个方法,这就是所有的View类的入口,这也和view是一个方法的说法不违背了。

下面我们就分别来看下Django内置的几个常用的View是怎么实现,以及怎么使用的。

TemplateView

下面是TemplateView的实现类图:

View类提供了as_view()类方法,注意,这个方法只能当作类方法使用,不能用在实例上,它返回一个内方法view(),在这个方法中,做的事情就是dispatch的事情,根据请求的方法,调用相应的方法去处理请求,如果你发送了一个GET请求,那么在view()方法中就会分发到get()方法中去处理。View类就主要封装了这个功能,这个功能是最高层的抽象,所有的view都需要有这个特性。

ContextMixin类则只是实现了一个方法,get_context_data(),这是为在渲染template的时候,提供了一个默认的context,一般子类都会重写这个方法的。

TemplateResponseMixin类,就是真正干事的类了,它在render_to_response()方法中,返回一个TemplateResponse对象,template用的就是类属性template_name指定的。

然后TemplateView继承上面的三个类,实现了get()方法,

def get(self, request, *args, **kwargs):
    context = self.get_context_data(**kwargs)
    return self.render_to_response(context)

组织了一下父类中的方法,得到context,然后传给render_to_response()去构造TemplateResponse对象,渲染模板,返回,就完事了。

以上,是Django给我们封装的,那么我们要怎么来用呢?其实,非常简单:

最简单的例子:

from django.conf.urls import patterns
from django.views.generic import TemplateView

urlpatterns = patterns(‘‘,
    (r‘^about/‘, TemplateView.as_view(template_name="about.html")),
)

使用Class-based View有两种方法,一个是在as_view()中直接传入参数,它会覆盖掉该View原有的属性,这种情况只适用于处理不复杂的情况,另外一个就是直接继承该View,然后覆盖其中的方法,属性等,实现自己想要的功能,如:

from django.views.generic import TemplateView

class AboutView(TemplateView):
    template_name = "about.html"

这样,在URLconf中,直接使用as_view()就可以了,不用传递参数:

from django.conf.urls import patterns
from some_app.views import AboutView

urlpatterns = patterns(‘‘,
    (r‘^about/‘, AboutView.as_view()),
)

是不是很简单?只需要几行代码,就实现了以前要很多代码才能实现的功能,这就是框架的力量啊。

ListView and DetailView

ListView和DetailView可以放到一起来说,这两个View类实现的非常的相似,下面两个类图,分别是ListView和DetailView的类图,从类图上看,就可以知道它们是多么的像,所不同的就只是把获取一个对象列表的函数,换成了获取一个对象的函数,大同小异。我对这些View类灵活的运用,就必须清楚它的内部结构,才能知道怎么去实现自定制。

ListView类图:

DetailView类图:

在这两个类图中,最关键的组件就是MultiObjectMixin和SingleObjectMixin这两个类了,他们实现的功能是从数据库中读取数据,并且构建要传入template的context。每个类都有一些属性和方法可以覆盖,实现自定制,比如可以覆盖context_object_name变量,用来指定传入template的context的对象的变量名;可以覆盖get_context_data()方法,用来将其他的变量放到context中;为queryset赋值,就可以自己指定这个View操作的对象(列表);或者是直接重写get_queryset()/get_object()方法,简单暴力。

注意,这两个类,也是继承自TemplateResponseMixin,也就是说它们也是直接返回的TemplateResponse对象。

好,我们来举一个简单的例子:

persons/urls.py

from django.conf.urls import patterns, include, url
from persons.views import PersonListView, PersonDetailView

urlpatterns = patterns(‘‘,
    url(r‘^persons/$‘, PersonListView.as_view(), name=‘list‘),
    url(r‘^persons/(?P<pk>\d+)/$‘, PersonDetailView.as_view(), name=‘detail‘),
)

persons/views.py

from persons.models import Person
from django.views.generic import ListView, DetailView

class PersonListView(ListView):
    model = Person
    context_object_name = ‘persons‘

class PersonDetailView(DetailView):
    model = Person

persons/templates/persons/person_list.html

<h2>Person List</h2>                                                                                                                                         

<ul>
  {% for person in persons %}
  <li><a href={% url detail person.id %}>{{ person.first_name }} {{ person.last_name }}</a></li>
  {% endfor %}
</ul>

persons/templates/persons/person_detail.html

<h2>Person Detail</h2>                                                                                                                                       

{{ object.first_name }} {{ object.last_name }}

可以看到两个View类只有简简单单几行代码,覆盖了几个属性,就把整个view的功能完成了,你可能要问几个问题:

  1. context变量是什么呢?
  2. template是哪个呢?
  3. DetailView的URLconf的Pattern该怎么写?一定要写pk吗?

呵呵,这就是约定的力量,我只能说一切都在源码中,看文档都不一定能彻底明白。

Refs

附录:

ListView类图代码:

@startuml

class ContextMixin{
    get_context_data(self, **kwargs)
}

class View{
    {abstract} as_view(cls, **initkwargs)
    dispatch(self, request, *args, **kwargs)
}

class TemplateResponseMixin{
    template_name = None
    response_class = TemplateResponse
    content_type = None

    render_to_response(self, context, **response_kwargs)
    get_template_names(self)
}

class MultipleObjectMixin{
    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

    get_queryset()
    get_context_object_name(self, object_list)
    get_context_data(self, **kwargs)
}

class BaseListView{
    get(self, request, *args, **kwargs)
}

class MultipleObjectTemplateResponseMixin{
    template_name_suffix = ‘_list‘
    get_template_names()
}

ContextMixin <|-- MultipleObjectMixin
MultipleObjectMixin <|-- BaseListView
View <|-- BaseListView
TemplateResponseMixin <|-- MultipleObjectTemplateResponseMixin
MultipleObjectTemplateResponseMixin <|-- ListView
BaseListView <|-- ListView

@enduml

DetailView类图代码:

@startuml

class ContextMixin{
    get_context_data(self, **kwargs)
}

class View{
    {abstract} as_view(cls, **initkwargs)
    dispatch(self, request, *args, **kwargs)
}

class TemplateResponseMixin{
    template_name = None
    response_class = TemplateResponse
    content_type = None

    render_to_response(self, context, **response_kwargs)
    get_template_names(self)
}

class SingleObjectMixin{
    queryset = None
    model = None
    slug_field = ‘slug‘
    context_object_name = None
    slug_url_kwarg = ‘slug‘
    pk_url_kwarg = ‘pk‘
    query_pk_and_slug = False

    get_object(self, queryset=None)
    get_queryset(self)
    get_context_object_name(self, object_list)
    get_context_data(self, **kwargs)
}

class BaseDetailView{
    get(self, request, *args, **kwargs)
}

class SingleObjectTemplateResponseMixin{
    template_name_suffix = ‘_detail‘
    template_name_field = None

    get_template_names()
}

ContextMixin <|-- SingleObjectMixin
SingleObjectMixin <|-- BaseDetailView
View <|-- BaseDetailView
TemplateResponseMixin <|-- SingleObjectTemplateResponseMixin
SingleObjectTemplateResponseMixin <|-- DetailView
BaseDetailView <|-- DetailView

@enduml
时间: 2024-07-31 10:26:37

转: django class base view 简单说明的相关文章

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

阅读目录 简述Django的View(视图) CBV和FBV Request对象和Response对象 Django组件(render,redirect)详解 一.简述Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面. 除此之外

Atitit.code&#160;base&#160;view&#160;视图的实现原理

Atitit.code base view 视图的实现原理 1. 视图的执行算法:1 2. 不可更新的视图:1 3. 关于视图的可插入性:insert2 4. 视图定义3 5. 调用3 1. 视图的执行算法: 存在两种执行算法: 1.  Merge:合并的执行方式,每当执行的时候,先将我们视图的sql语句与外部查询视图的sql语句,混合在一起,最终执行: 2.  Temptable:临时表模式,每当查询的时候,将视图所使用的select语句生成一个结果的临时表,再在当前的临时表内进行查询. 指的

Django框架 之 view视图

浏览目录 概述 简单的视图 HttpRequest对象 CBV和FBV 给视图加装饰器 Request对象 Response对象 JsonResponse对象 Django shortcut functions 一.概述 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项

Django视图系统(view)

一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面. 一. CBV和FBV 1. FBV是基于函数的view def add_class(request): if request.method == "POST": class_name = reque

Django视图(View)

Django 视图 声明:文章部分内容来源https://www.cnblogs.com/maple-shaw/articles/9285269.html 视图的概念:一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片 视图的规范:无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面.除此之外没有更多的要求了--可以说

Django创建App并简单实现登录模块

Django创建App并简单实现登录模块 什么是Django的APP? 此APP非andriodAPP.Django的APP可以理解为一个网站中的一个模块,我们可以将每个模块都单独写成一个APP,这样可以让项目变得相对整洁且更加好维护起来. 如何创建App? 1.创建Django工程 - BlogPorject django-admin startproject BlogPorject 2.创建App django-admin startapp application App目录介绍: appl

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

问题: Django中,view的书写方式有两种,一种是def函数方式,一种是class方式,函数方式通过@login_required装饰器标记函数,就必须通过用户验证,而类,则没办法通过此方法进行标记 那,如何解决这个问题? 利用类的继承方式,写一个基类,需要验证的class view类,首先继承这个基类,后面所有通过此类的url都需要进行用户验证登录,因为可能有许多的view需要使用该类,需要独立出来,建立在utils目录下,起名mixin_is_login.py,然后在各种需要的view

django框架The view account.views.register didn&#39;t return an HttpResponse object.错误的解决办法

对提交方法不是POST的方法没有添加分支进行判断 1. 注意# 判断post/get 分支判断提交方法 django框架The view account.views.register didn't return an HttpResponse object.错误的解决办法 原文地址:https://www.cnblogs.com/bigfacecatovo/p/11980389.html

Django drf:cbv(class base view)源码分析

cbv是基于类的视图 # 首先要在路由层配置: # 找到类绑定方法as_view # 点开dispatch的方法 # http_method_names其实就是方法的列表 整个流程: 1.写一个基于类的视图 2.然后在路由层配置,第二参数写as_view,加括号执行 3.由于父级中没有需要到view中找方法,as_view方法其实是一个闭包函数,返回的一个函数地址加括号执行 4.as_view中执行了dispatch方法,就是将视图类中的参数拿到,和列表中方法比较,如果有返回执行,没有就提示错误