zoukankan      html  css  js  c++  java
  • 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
     
  • 相关阅读:
    Core Animation 文档翻译—附录C(KVC扩展)
    Core Animation 文档翻译—附录B(可动画的属性)
    Core Animation 文档翻译—附录A(Layer样貌相关属性动画)
    Core Animation 文档翻译 (第八篇)—提高动画的性能
    Core Animation 文档翻译 (第七篇)—改变Layer的默认动画
    Core Animation 文档翻译 (第六篇)—高级动画技巧
    Core Animation 文档翻译 (第五篇)—构建Layer的层次结构
    用Markdown快速排版一片文章
    Core Animation 文档翻译 (第四篇)—让Layer的content动画起来
    Core Animation 文档翻译(第三篇)—设置Layer对象
  • 原文地址:https://www.cnblogs.com/limaomao/p/9638127.html
Copyright © 2011-2022 走看看