类视图引入

以函数的方式定义的视图成为函数视图,函数视图便于理解。但是遇到一个视图对应的路径提供了多种不同HTTP请求方式的支持时,就需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。 第5天:基于类的视图与中间件 随笔 第1张
def register(request):
    """处理注册"""

    #获取请求方法,判断是GET/POST请求
    if request.method == 'GET':
        #处理GET请求,返回注册页面
        return render(request, 'register.html')
    else:
        #处理POST请求,实现注册逻辑
        return HttpResponse('这里实现注册逻辑')
函数视图示例

在Django中也可以使用类来定义一个视图,称为类视图

第5天:基于类的视图与中间件 随笔 第3张
def register(View):
    """类视图 处理注册"""
    
    def get(self, request):
        "处理GET请求, 返回注册页面"
        return render(request, 'register.html')
    
    def post(self, request):
        " 处理POST请求,实现注册逻辑"
        return HttpResponse('这里实现注册逻辑')
类视图示例

类视图好处:

  • 代码可读性好
  • 类视图相对于函数视图通过继承具有更高的可复用性

 

类视图的定义与使用

我们要想使用类视图必须继承View

from django.views.generic import View

第5天:基于类的视图与中间件 随笔 第5张
from django.views.generic import View


class DemoView(View):
    def get(self, request):
        return HttpResponse('get page')
    
    def post(self, request):
        return HttpResponse('post page')
DemoView

路由那里,我则需要使用该视图的as_view方法转换为函数

第5天:基于类的视图与中间件 随笔 第7张
from .views import DemoView

urlpatterns = [
    url(r'^demo/$', DemoView.as_view(), name='demo')
]
路由配置

 

类视图实现的原理

 按住ctrl,点击as_view

第5天:基于类的视图与中间件 随笔 第9张

第5天:基于类的视图与中间件 随笔 第10张
@classonlymethod
def as_view(cls, **initkwargs):
    """
    Main entry point for a request-response process.
    """
    ...

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)     #cls就是DemoView类,生成对象
        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)
    view.view_class = cls
    view.view_initkwargs = initkwargs

    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)
相关源码

 

在类视图中使用装饰器

我们知道在函数视图中,可以如下使用装饰器 

第5天:基于类的视图与中间件 随笔 第12张
def my_decorator(view_func):
    def wrapper(*args, **kwargs):
        print('装饰器被调用')
        return view_func(*args, **kwargs)
    return wrapper

@my_decorator
def func_demo(request):
    return HttpResponse('func_demo')
函数视图使用装饰器

在类视图中使用为函数视图准备的装饰器时,不能直接添加装饰器,需要使用method_decorator将其转换为适用于类视图方法的装饰器。

第5天:基于类的视图与中间件 随笔 第14张 

第5天:基于类的视图与中间件 随笔 第15张

 

类视图多继承& Minx扩展类

使用面向对象多继承特性,可以通过定义父类(作为扩展类),在父类中定义想要想类视图补充的方法,类视图继承这些扩展类,便可实现代码服用。定义父类名称通常以Mixin结尾

第5天:基于类的视图与中间件 随笔 第16张
class ListModelMixin(object):
    """list扩展类"""
    def list(self, request, *args, **kwargs):
        print('查询多条数据')


class CreateModelMixin(object):
    """create扩展类"""
    def create(self, request, *args, **kwargs):
        print('新增一条数据')


class DepartmentView(CreateModelMixin, ListModelMixin, View):
    """
    同时继承两个扩展类,复用list和create方法
    """
    def get(self, request):
        self.list(request)
        return HttpResponse('get page')

    def post(self, request):
        self.create(request)
        return HttpResponse('post page')
示例

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄