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


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

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

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

      class UserInfoView(View):

        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')

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

    上述示例代码就可以根据同一个url执行不同的方法时去执行不同的操作

    CBV实现的源码分析:
      1、请求进来,路由找到试图类并执行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))

        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

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

      3、因为试图类本身没有定义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中针对重要的数据操作,想要实现数据库的事件特性而添加的装饰器:

    1、方法一:

    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

    2、方法二:
    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
     
  • 相关阅读:
    Laravel源码解析 — 服务容器
    Java日志框架中需要判断log.isDebugEnabled()吗?
    使用C语言实现线性表
    new-delete
    webrtc-AudioprcessingModule 3A算法demo
    关于iPhone语音备忘录访问
    关于音频通话耗时
    关于Windows上使用OpenAL API声源音效
    c++ 类术语
    二分法查找
  • 原文地址:https://www.cnblogs.com/limaomao/p/9638127.html
Copyright © 2020-2023  润新知