Django 中有两种编写方式,FBV 和 CBV,那么什么是 FBV,CBV 又是什么呢?

一、什么是 CBV

  • FBV(function base views) 就是在视图里使用函数处理请求(常见)。
  • CBV(class base views) 就是在视图里使用类处理请求。

示例:

1、project/urls.py

  1. from django.contrib import admin
  2. from django.urls import path
  3. from app.views import IndexView
  4. urlpatterns = [
  5. path('admin/', admin.site.urls),
  6. path('index/', IndexView.as_view()),
  7. ]

2、app/views.py

  1. from django.shortcuts import render, HttpResponse
  2. from django.views import View
  3. class IndexView(View):
  4. def get(self, request, *args, **kwargs):
  5. print('get')
  6. return HttpResponse('GET')
  7. def post(self, request, *args, **kwargs):
  8. print('post')
  9. return HttpResponse('POST')

可以看到所有的请求都是在类 IndexView 中处理的,它继承 View,不管是什么请求,都可以匹配到。

二、源码分析

1、CBV 在进行路由匹配时,执行 as_view() 方法,它是类 View 中的一个方法,源码 base.py

  1. class View:
  2. @classonlymethod
  3. def as_view(cls, **initkwargs):
  4. """Main entry point for a request-response process."""
  5. for key in initkwargs:
  6. if key in cls.http_method_names:
  7. raise TypeError("You tried to pass in the %s method name as a "
  8. "keyword argument to %s(). Don't do that."
  9. % (key, cls.__name__))
  10. if not hasattr(cls, key):
  11. raise TypeError("%s() received an invalid keyword %r. as_view "
  12. "only accepts arguments that are already "
  13. "attributes of the class." % (cls.__name__, key))
  14. def view(request, *args, **kwargs):
  15. self = cls(**initkwargs)
  16. if hasattr(self, 'get') and not hasattr(self, 'head'):
  17. self.head = self.get
  18. self.request = request
  19. self.args = args
  20. self.kwargs = kwargs
  21. return self.dispatch(request, *args, **kwargs)
  22. view.view_class = cls
  23. view.view_initkwargs = initkwargs
  24. # take name and docstring from class
  25. update_wrapper(view, cls, updated=())
  26. # and possible attributes set by decorators
  27. # like csrf_exempt from dispatch
  28. update_wrapper(view, cls.dispatch, assigned=())
  29. return view

2、从上面的源码中我们可以看到 as_view(),返回 view() 方法。而 view() 又调用执行 self.dispatch(request, *args, **kwargs) 方法:

  1. def dispatch(self, request, *args, **kwargs):
  2. """
  3. 首先要判断请求方法是不是在 self.http_method_names 中(即允许的方法列表中)
  4. 通过反射,匹配相应方法 get、post、put、delete 等
  5. """
  6. if request.method.lower() in self.http_method_names:
  7. handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
  8. else:
  9. handler = self.http_method_not_allowed
  10. return handler(request, *args, **kwargs) # 如果匹配上了,就执行它,get(requesr, *args, **kwargs)

http_method_names

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

3、因此大致的执行流程为:

  • 请求过来先执行 URL 中的 as_view() 方法
  • as_view() 返回 view() 方法
  • view() 方法又调用执行 dispatch() 方法
  • dispatch() 中通过反射的方式来匹配相应的请求,是 get 请求,就执行 get() 方法,如果是 post 请求的就执行 post() 方法。

三、重写 dispatch

从上面我们指定 CBV 中,请求过来,执行相应视图函数之前,都会先执行 dispatch() 方法。那么如果我们想在处理请求前执行某个方法或者就打印点别的东西,我们可以重写它。

方法一

  1. from django.shortcuts import render, HttpResponse
  2. from django.views import View
  3. class IndexView(View):
  4. def dispatch(self, request, *args, **kwargs):
  5. print('before...')
  6. func = getattr(self, request.method.lower())
  7. ret = func(self, request, *args, **kwargs)
  8. print('after...')
  9. return ret
  10. def get(self, request, *args, **kwargs):
  11. print('get')
  12. return HttpResponse('GET')
  13. def post(self, request, *args, **kwargs):
  14. print('post')
  15. return HttpResponse('POST')

运行结果如下:

  1. before...
  2. get
  3. after...

当有很多个类的时候,不可能每个类都写一个,可以写一个基类,其他类继承基类即可:

  1. class BasePatch(object):
  2. def dispatch(self, request, *args, **kwargs):
  3. print('before...')
  4. func = getattr(self, request.method.lower())
  5. ret = func(self, request, *args, **kwargs)
  6. print('after...')
  7. return ret
  8. class IndexView(BasePatch, View):
  9. pass

这样 IndexView 就会先去找基类 BaseView 中的 dispatch() 方法,而不是 View 中的。


方法二

也可以继承父类的 dispatch(),不用自己写反射逻辑:

  1. class BasePatch(object):
  2. def dispatch(self, request, *args, **kwargs):
  3. print('before...')
  4. ret = super(BasePatch, self).dispatch(request, *args, **kwargs)
  5. print('after...')
  6. return ret

四、CSRF

CBV 中如果想给某个函数免除 csrf_token 认证,可以通过装饰器的形式实现,但是需要注意的是,装饰器必须装饰在类上或者 dispatch 上

方法一

  1. from django.utils.decorators import method_decorator
  2. from django.views.decorators.csrf import csrf_exempt
  3. class IndexView(View):
  4. @method_decorator(csrf_exempt) # 这句
  5. def dispatch(self, request, *args, **kwargs):
  6. print('before...')
  7. func = getattr(self, request.method.lower())
  8. ret = func(self, request, *args, **kwargs)
  9. print('after...')
  10. return ret

方法二

装饰在类上,不用 dispatch

  1. @method_decorator(csrf_exempt, name='dispatch')
  2. class IndexView(View):
  3. def get(self, request, *args, **kwargs):
  4. pass

Django 之 CBV的更多相关文章

  1. Django的CBV与FBV

    FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以不再赘述. CBV CBV(class base v ...

  2. Django的 CBV和FBV

    FBV CBV 回顾多重继承和Mixin 回到顶部 FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以 ...

  3. Django 之 CBV & FBV

    FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django随笔中,一直使用的是这种方式,不再赘述. CBV CBV(class base views) ...

  4. Django之CBV和FBV

    Django之CBV和FBV CBV和FBV是C和F的区别: C是Class,F是Function 在请求中,有GET请求和POST请求. 在写CBV时,url是可以对应一个类的,在类中,分别写出GE ...

  5. django中CBV

    08.13自我总结 django中CBV 一.django处理业务逻辑的两种方式 FBV (function based views):使用函数来处理业务逻辑 CBV (class based vie ...

  6. django补充CBV和FBV模式

    django补充CBV和FBV模式FBV模式---函数:经常用的方式CBV模式---类CBV中url连接时函数名后面要接.as_view()class index(views.View): @... ...

  7. 使用Ajax (put delete ) django原生CBV 出现csrf token解决办法

    原因 django原生CBV中对于 Ajax put 或 delete 请求进行封装时,会把请求数据放在 request.body里, 所以获取不到csrf token 方式一: 关闭csrf 中间件 ...

  8. Django 的 cbv

    Django 的 cbv 正如我们了解到的,Django 写视图函数有两种写法:cbv 和 fbv.cbv 提倡使用类来写,fbv 使用函数来 写.当然为了代码的重复行,官方更推荐使用 cbv. 写 ...

  9. django中CBV源码分析

    前言:Django的视图处理方式有两种: FBV(function base views) 是在视图里基于函数形式处理请求. CBV(class base views)是在视图里基于类的形式处理请求. ...

  10. Django之 CBV和FBV

    FBV FBV(function base views) 就是在视图里使用函数处理请求. CBV CBV(class base views) 就是在视图里使用类处理请求. Python是一个面向对象的 ...

随机推荐

  1. css3中的box-sizing常用的属性有哪些?分别有什么作用?

    content-box:默认标准盒模型,总宽=width+padding+border+margin border-box:IE标准,怪异盒模型,总宽=width+margin inherit:从父元 ...

  2. selenium--单选下拉列表

    下拉选择 from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get(&q ...

  3. 【字符串】【P5830】 【模板】失配树

    [字符串][P5830] [模板]失配树 Description 给定一个长度为 \(n\) 的字符串 \(S\),有 \(m\) 次询问,每次询问给定 \(S\) 的两个前缀,求它们的最长公共 bo ...

  4. vue监听当前页面的地址变化/路由变化

    转载自: Heap Stack(Pingbook) https://pingbook.top/vue-watch-current-url-route-change/

  5. 安装gerrit服务器

    一.环境准备 1.Java环境 gerrit依赖,用于安装gerrit环境. 下载:jdk-7u79-linux-x64.tar.gz http://www.oracle.com/technetwor ...

  6. 避免因为Arcgis Server服务设置不当导致Oracle Process溢出的方法

    我之前写过一篇文章<arcsoc进程无限增长导致oracle processes溢出>(见链接:https://www.cnblogs.com/6yuhang/p/9379086.html ...

  7. python 实例

    进度条 import sys, time class ShowProcess(object): """ 显示处理进度的类 调用该类相关函数即可实现处理进度的显示 &quo ...

  8. IAR_STM32_CCM内存使用

    在IAR中,硬件环境为STM32F464单片机,额外的CCM不能用DMA访问,但可以作为内部额外扩充RAM使用 修改文件中的内容为: define symbol __ICFEDIT_region_RO ...

  9. asp.net core 系列之允许跨域访问-1(Enable Cross-Origin Requests:CORS)

    接上篇的允许跨域 4.CORS 策略(Policy)的选项 这里讲解Policy可以设置的选项: 设置允许的访问源 设置允许的HTTP methods 设置允许的请求头(request header) ...

  10. MVC学习笔记(六)---遇到的小问题汇总

    一.MVC中Controller中返回两个对象的写法如下: , msg = "成功", user = user, userInfo = person }); 二.前台向后台传入带有 ...