Please enable Javascript to view the contents

Django 类视图

 ·  ☕ 4 分钟

Django中有两种视图,一种是函数式视图,另一种是类视图。视图的作用主要是,用于填充逻辑,返回响应体。函数式视图难以扩展,代码复用率低。而类视图可以利用继承、Mixins,快速复用、扩展功能。本文主要讨论了,Django对类视图的处理逻辑,类视图装饰器实现。

1. Django的视图

Django的URL解析器,将一个HttpRequest对象和相应的参数传递给一个可调用的函数,并期待其返回一个HttpResponse对象。这个可调用的函数,就是视图函数。

1.1 函数式视图

views.py

1
2
3
4
5
6
7
8
9
from django.http import HttpResponse
  
def my_view(request):
    if request.method == 'GET':
        # 填充逻辑
        return HttpResponse('result')
    if request.method == 'POST':
        # 填充逻辑
        return HttpResponse('result')

urls.py

1
2
3
4
5
6
7
# urls.py
from django.conf.urls import patterns
import .views as home_view
 
urlpatterns = patterns('',
    (r'^my_view/', home_view.my_view)
)

函数式视图(FBV)只使用在定制错误,或那些使用类视图实现时会很复杂的情况。

1.2 类视图

views.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.http import HttpResponse
from django.views.generic.base import View
  
class MyView(View):
    def get(self, request):
        # 填充逻辑
        return HttpResponse('result')
    def post(self, request):
        # 填充逻辑
        return HttpResponse('result')

urls.py

1
2
3
4
5
6
7
# urls.py
from django.conf.urls import patterns
from .views import MyView
 
urlpatterns = patterns('',
    (r'^about/', MyView.as_view()),
)

为了解耦视图和URL、代码复用,Django提供了类视图。

类视图(CBV)提供了一个as_view()静态方法,调用该方法,会创建一个类的实例。然后调用实例的dispatch()方法,dispatch()方法会根据request的请求类型,调用相应实例的同名方法。如果没有找到对应的方法,将引发一个HttpResponseNotAllowed异常。

Django提供的一系列类视图类,都继承自一个View基类(django.views.generic.base.View),在这个基类里实现了与 URL的接口(as_view)、请求方法匹配(dispatch)和一些其他的基本功能。比如 ,RedirectView 实现了 HTTP 重定向,TemplateView 新增了渲染模板的方法。

django.views.generic.base.py 中View类as_view和dispatch方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@classonlymethod
def as_view(cls, **initkwargs):
    for key in initkwargs:
        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__))
        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)
        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)

    update_wrapper(view, cls, updated=())

    update_wrapper(view, cls.dispatch, assigned=())
    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)

2. Django视图Mixin类

Django将基本的HTTP请求和响应,抽象封装成类。在使用过程中,只需要将这些基类聚合,按照需求的方式重写或者直接复用。这些基类称之为Mixin。

在django.views.generic包中,除了base提供了构成cbv最基础的几个Mixin,以及cbv的基类View,还提供了四个模块,

  • detail,显示详细数据,SingleObjectMixin,SingleObjectTemplateResponseMixin
  • list,显示列表,MultipleObjectMixin,MultipleObjectTemplateResponseMixin
  • edit,提供新增和编辑的功能,DeletionMixin,FormMixin,
  • dates,年月日相关的显示和获取,YearMixin, MonthMixin, DayMixin, WeekMixin, DateMixin

一个View Class可以继承多个Mixin,但是只能继承一个View(包括其子类)。

3. 类视图装饰器

3.1 修饰dispatch

dispatch装饰器,将影响到全部的视图类方法函数。Django 1.9开始method_decorator支持name参数,可以指定方法,例如,name=‘get’,表示仅修饰get函数。如果有多个装饰器需要配置,@method_decorator也接受列表参数,可以同时装配多个装饰器。

1
2
3
4
5
6
7
8
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic.base import View
 
class MyView(View):
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)

带参数的装饰器用法:
@method_decorator(login_required_by_role(‘super’))

3.2 修饰视图类

修饰类和修饰dispatch一样,也会影响全部HTTP方法。

1
2
3
4
5
6
7
8
9
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic.base import View
 
@method_decorator(login_required)
class MyView(View): 
    
    def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)

3.3 URLConf中配置装饰器

1
2
3
4
5
6
7
8
9
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = [
    url(r'^about/$', login_required(TemplateView.as_view(template_name="secret.html"))),
    url(r'^vote/$', permission_required('polls.can_vote')(VoteView.as_view())),
]

4. 参考


微信公众号
作者
微信公众号