django类视图简单使用和源码解析

django的类视图,CBV
  咱们在开始接触django的时候,习惯于使用函数编写视图,即FBV。使用FBV时,咱们只须要在路由匹配时,对应的路由下找到这个函数就能够了,这样作看似很和谐,可是有的时候,譬如说,当咱们须要根据同一个url请求方法的不一样而去执行不一样的操做时,若是使用FBV去编写视图,那么咱们就须要在视图函数中不断地去执行if request.method=='请求方法' 去判断要去执行什么内容,此时的代码就显得不是很优雅。可是此时若是咱们使用CBV的方式来编写视图,一样的需求,代码就会显得优雅不少,下面就让我来介绍一下CBV的具体实现:python

在django中使用CBV编写视图:
  一、首先咱们自定义的视图类须要继承django.views.View类
  二、在视图类中定义以'请求方法名称小'写为名称的方法,这样在执行不一样的请求方法的时候就回去自动执行对应的函数
  三、在路由映射的时候,要执行这个试图类的as_view()方法,注意这个方法继承自django.views.View数据库

示例代码以下:
'views.py'文件:
  from django.views import View
  from django.http import HttpResponsedjango

  class UserInfoView(View):app

    def get(self, request, *args, **kwargs):
      return HttpResponse('get user')函数

    def post(self, request, *args, **kwargs):
      return HttpResponse('post user')源码分析

    def delete(self, request, *args, **kwargs):
      return HttpResponse('delete user')post

 

'url.py'文件
  from app import views
  urlpatterns = [
    path('user/', views.UserInfoView.as_view())
  ]atom

上述示例代码就能够根据同一个url执行不一样的方法时去执行不一样的操做url

 

CBV实现的源码分析:
  一、请求进来,路由找到试图类并执行as_view方法,执行这个方法时其实会返回一个view函数,所以能够看作请求进来以后会先执行试图类的view方法,源码以下:
  @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))spa

    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)
    view.view_class = cls
    view.view_initkwargs = initkwargs

    update_wrapper(view, cls, updated=())

    update_wrapper(view, cls.dispatch, assigned=())
    return view

  二、从上面的源码中能够看出执行view方法,实际上就是返回self.dispatch方法,也就是说会去执行self.dispatch方法

  三、由于试图类自己没有定义dispatch方法,那么在执行dispatch方法的时候就须要去其父类里面查找,而父类里面的dispatch方法则会根据请求方法的不一样基于python类的反射去找到相应的方法,而后执行,这样就会自动实现根据请求方法的不一样去执行不一样的内容了,dispatch方法的源码以下:
  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)

 

CBV之添加装饰器:

在咱们使用函数试图FBV的时候,若是咱们想要给其加上一个装饰器,直接加就能够了,例如,在建立django项目的时候,默认全局使用csrf防御,若是咱们想要在某个函数试图上不使用CSRF保护,那么咱们能够给这个视图函数直接添加一个装饰器便可,示例代码以下:

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def index(request):
return HttpResponse('index')

 

可是,当咱们想要给CBV添加装饰器,那么咱们须要作的就不是在其内部的方法上添加,若是和FBV同样直接添加到方法上,那么这不会起任何做用。在CBV上添加装饰器的方法有两种,第一种是重写父类的dispatch方法,并将装饰器添加到dispatch方法上,与此同时在CBV上添加装饰器最好使用django.utils.decorators.method_decorator方法进行包裹。第二种方法则是直接添加在类上,只不过这时你须要使用django.utils.decorators.method_decorator来进行封装。下面的例子是咱们在django中针对重要的数据操做,想要实现数据库的事件特性而添加的装饰器:

一、方法一:

from django.utils.decorators import method_decorator
from django.db import transaction

class OrderView(View):
@method_decorator(transaction.atomic)
def dispatch(self, request, *args, **kwargs):
return super(OrderView, self).dispatch(request, *args, **kwargs)

def get(self, request, *args, **kwargs):
pass

def post(self, request, *args, **kwargs):
pass

def patch(self, request, *args, **kwargs):
pass

def delete(self, request, *args, **kwargs):
pass

二、方法二:
from django.utils.decorators import method_decorator
from django.db import transaction

@method_decorator(transaction.atomic, name='dispatch')
class OrderView(View):
def get(self, request, *args, **kwargs):
pass

def post(self, request, *args, **kwargs):
pass

def patch(self, request, *args, **kwargs):
pass

def delete(self, request, *args, **kwargs):
pass
相关文章
相关标签/搜索