• django—视图相关


    FBV与CBV

      FBV:function based view   基于函数的视图

      CBV:class based view  基于类的视图

      

      CBV的定义:

        from django.views import View

        class Cbv(View):

          def get(self,request):

            # 专门处理get请求的函数

          def post(self,request):

            # 专门处理post请求的函数

      CBV的路由配置:

        path('cbv_test',Cbv.as_view())

        as_view()的返回结果是一个处理好的FBV

      

      CBV和FBV:

        CBV能够直接根据请求方式直接匹配到对应的方法执行,FBV则需要在视图函数内部,通过request.method来判断请求方式,以便做不同的逻辑处理。

        不同的是,如果CBV中没有定义对应请求方式的处理方法的话,会报错。而FBV中没有对应请求方式的处理逻辑的话也不会有太大问题。

      

      as_view()源码:  

      @classonlymethod
      def as_view(cls, **initkwargs):
       """Main entry point for a request-response process."""
      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.setup(request, *args, **kwargs)
      if not hasattr(self, 'request'):
       raise AttributeError(
       "%s instance has no 'request' attribute. Did you override "
      "setup() and forget to call super()?" % cls.__name__
      )
      return self.dispatch(request, *args, **kwargs)
      view.view_class = cls
      view.view_initkwargs = initkwargs

      # take name and docstring from class
      update_wrapper(view, cls, updated=())

      # and possible attributes set by decorators
      # like csrf_exempt from dispatch
      update_wrapper(view, cls.dispatch, assigned=())
      return view

      as_view是定义在View类里的类方法,CBV继承了View类,所以也就有了as_view方法。

      从源码上看,CBV调用了as_view方法,最后还是会返回一个函数地址,也就不违反路由配置中对于第二个参数要是一个函数地址的限制。

      所以,主要看as_view内部的view函数:

        request:wsgi封装好的请求对象,和FBV里拿到的request一模一样

        cls:表示当前调用该函数的类,也就是自定义的CBV

        self:就是由CBV实例化的对象

        然后将request赋值给当前CBV实例化的对象,所以CBV内部self.request和某个请求方法的request参数是同一个request。

        setup方法内部实现方式如下

        def setup(self, request, *args, **kwargs):
         """Initialize attributes shared by all view methods."""
        self.request = request
        self.args = args
        self.kwargs = kwargs

        最终返回View类中的dispatch方法的结果,作为返回值。

        接着看dispatch方法内部做了些什么:    

        def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        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)

        首先获取当前请求的结果(字符串)并将其小写后,判断其是否在http_method_names列表中,也就意味着判断该请求方式在当前配置下是否允许。

        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

        该列表定义在View类内部的最上方,也就是说如果自定义某个CBV,想配置哪些请求方式是允许的,只要在CBV内部重写该列表即可。

        在当前请求方式是允许的情况,通过反射机制获取当前请求方式在CBV中对于的处理方法,如果获取不到对应的处理方法(即在CBV中没有定义,或者定义方法名不符合规范,因为它通过反射机制是要拿到方法名是小写的方法),则表明该方法无效。那么当前请求将会得到405错误页面,也就是先前说的,CBV必须要定义在许可范围内的请求处理方法,否则会出错。

        def http_method_not_allowed(self, request, *args, **kwargs):
         logger.warning(
        'Method Not Allowed (%s): %s', request.method, request.path,
        extra={'status_code': 405, 'request': request}
        )
        return HttpResponseNotAllowed(self._allowed_methods())

        如果通过反射机制得到了相应请求的处理方法,则在调用该方法后,将该方法的结果作为返回值返回。也就是将相应请求的处理方法的response对象返回。

        也就是说CBV内部处理请求的方法,正在被执行的地方就在View类中的dispatch方法内。

        如果想要在处理请求的方法的执行前后,增加一些操作,可以在CBV内部重写 dispatch然后在调用父类的dispatch前后增加想要做的操作,如函数执行计时等。

      给CBV加装饰器

        需要先导入method_decorator

        from django.utils.decorators import method_decorator

        1、然后在CBV内部对应方法上加装饰器  @method_decorator(对应的装饰器地址)

        2、如果只想给单个请求方式对应的处理方法加上装饰器的话,直接就在对应方法上加即可

           如果想让所有请求方式对应的处理方法都加上装饰器的话,可以在CBV内部重写View类的dispatch方法,然后super调用View类的dispatch,最后把装饰器加在重写后的dispatch方法上。

        3、直接将装饰器加在CBV上@method_decorator(对应的装饰器地址,name='对应的方法名')

           或者@method_decorator(对应的装饰器地址,name='dispatch')

    request对象

      request.method:获取当前的请求方式

      request.GET:获取URL上携带的参数

      request.POST:获取post请求提交的数据

      request.path_info:获取url的路径(不包括域名和携带的参数)

      request.get_full_path():获取url的路径(包括携带的参数)

      request.body:获取请求体中的数据,得到的结果为bytes类型

      request.scheme:返回请求协议(http/https)

      request.encoding:获取提交数据的编码方式,若为None则默认使用utf-8

      request.COOKIES:cookie字典,键值均为字符串

      request.session:session信息

      request.FILES:获取上传的文件

      request.META:返回一个字典,里面包含请求头的信息

      request.user:一个AUTH_USER_MODEL类型对象,表示当前登录的用户

      request.get_host():返回请求的原始主机,若主机位于多个代理后,get_host()将失效

      request.is_secure():判断请求是否安全(即是否是https发起的),返回布尔值

      request.is_ajax():判断请求是否是ajax发起的

    Response对象

      HttpResponse("字符串")

      render(request, "模板", {数据字典})

      render_to_string("模板", {数据字典})   返回渲染后的模板文件的字符串

      redirect("地址")  重定向

      JsonResponse()返回json格式的响应,默认只能序列化字典 序列化其他需要加safe参数

      

      render方法中,调用了render_to_string将渲染后的模板文件的字符串,通过HttpResponse("字符串")返回给浏览器

        def render(request, template_name, context=None, content_type=None, status=None, using=None):
        """
        Return a HttpResponse whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
        """
        content = loader.render_to_string(template_name, context, request, using=using)
        return HttpResponse(content, content_type, status)

      redirect("地址")本质就是将响应头中的Location值set为重定向的地址,并将状态码设置为301或者302返回给浏览器。

      以下代码同样能实现redirect方法的功能:

        ret = HttpResponse('', status = 301)

        ret['Location'] = '地址'

        return ret

      补充:临时重定向(响应状态码:302)和永久重定向(响应状态码:301)

      

        

        

  • 相关阅读:
    Oracle 临时事务表 全局临时表_global temporary table
    js String Trim函数
    解决Navicat Error: Missing required libmysql_d.dll
    win8双屏敲代码
    条件注释判断浏览器
    Eclipse 中Alt+/快捷键失效的解决办法。
    解决java写入xml报错org.w3c.dom.DOMException:DOM002 Illeg
    用解释计划评估创建索引后对单表查询效率的影响
    在某文件夹查找以日期命名的目录,如果早已目标时间则删除之
    (Python)正则表达式进行匹配
  • 原文地址:https://www.cnblogs.com/yamx/p/13264202.html
Copyright © 2020-2023  润新知