Django FBV与CBV,CBV源码剖析

一、FBV与CBV

1.FBV基于函数的视图(Function base view)

  • 之前我们在视图层都用的是基于函数的视图,使用函数来处理不同的请求。

基于视图的函数我们学习Django的时候就就已经在使用了,示例如下:

urls.py文件

urlpatterns = [
    path("login/", views.login),
]

views.py文件

from django.shortcuts import render,HttpResponse

def login(request):
    if request.method == "GET":
        return HttpResponse("GET 方法")
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        if user == "shawn" and pwd == "123456":
            return HttpResponse("POST 方法")
        else:
            return HttpResponse("POST 方法1")

如果我们在浏览器中直接访问 http://127.0.0.1:8000/login/ ,输出结果为:GET 方法

2.CBV基于类的视图(Class base view)

基本介绍

  • 采用采用面向对象的方法写视图文件。
  • 使用类来处理视图层的请求

基本使用

视图层views.py文件

from django.views import View

def test_func(request):
    return render(request,'test.html')
class MyView(View):
    def get(self,request):
        return HttpResponse('触发了get方法--->')

    def post(self,request):
        return HttpResponse('触发了post方法--->')

路由层urls.py文件

from django.urls import path,re_path,include
from app02 import views

urlpatterns = [
    re_path(r'^test/',views.test_func),
    re_path(r'^func',views.MyView.as_view())
]

模板层test.html

<div>
    <form action="/func/" method="post" enctype="multipart/form-data">
        <input type="file">
        <input type="submit">
    </form>
</div>

实现效果:用户使用get方式提交数据触发get方法, 用户使用post方式提交数据触发post方法

image-20210318162922305

image-20210318162957803

image-20210318163008337

问题:那么为什么就能根据不同的操作来触发不同发那个发的执行呢?

二、CBV源码分析

1.储备知识

  • 面向对象属性查找顺序
  • 类方法特性
  • 反射中getattr( ) 提前了解一下

2.突破口

re_path(r'^func',views.MyView.as_view())  # as_view() 是什么东西

我们 Ctrl + 点击查看其源码

发现它是一个类方法, 查看其整体结构(只看框起来的即可, 其他的不用管), 该方法内部有一个 view 方法, 并且返回值是 view 的内存地址, 类似于闭包函数

image-20210318165421598

于是我们就可以得到一些初步结果

re_path(r'^func',views.MyView.as_view())  # 等同于下面
re_path(r'^func',views.view) # 看着是不是与普通的路由没有什么区别了 : 通过匹配触发视图函数的运行

那么 view 是一个什么样的函数呢? 现在突破口变成了 view 方法了

我们再看其源码(只看框起来的即可,其他的不用管) :

image-20210318170758491

"self = cls(**initkwargs)"
# cls是什么? 记得上面的类方法吗? 类调用时传入类本身
# 我们是通过MyView来调用as_view的, 那么cls也就是MyView
# 类加括号实例化得到对象self, 这个self就是我们自己的类产生的对象 : self=MyView(**initkwargs),我们不用去管里面的参数
# 接下来看看view的返回值 : self.dispatch(request, *args, **kwargs)
# 也就是去MyView类实例出的对象里面去找dispatch方法并执行,很显然self对象中没有该方法,于是去类中去找,也没有
# 最后到父类View中去找,发现就在as_view类方法的下面找到了

image-20210318171904242

我们在看它下面的逻辑代码

image-20210318172023112

逻辑很简单,使用了反射的知识点

# 先是拿到当前请求方式的大写字符转成小写, 然后判断在不在后面的 self.http_method_names 里面
# Ctrl+点击 看看这是个什么东西 : 
'http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']'
# 发现是8种常用的请求方式列表, 接着返回dispatch源码查看,为了方便我们假设现在的是get请求方式
# 判断get请求在请求列表里面,于是执行紧跟其下的代码...我们先看看getattr()得到的是什么结果
# 判断我们的self是否有名叫get的属性或方法,如果有则返回该属性的值或方法的内存地址,否则返回 self.http_method_not_allowed, 这是个啥,我们 Ctrl+点击 也来看看:

image-20210318173044730

# 原来是一个报错信息 : 提示方法不允许,整理下思路,也就是说self中有get返回值或者内存地址,没有则报错
# 很显然我们的self是有get这个名字的,并且是一个方法,于是将get方法的内存地址赋值给handler
# 我们再来看dispatch的返回值 : handler + (括号), 不就是执行该方法吗!也就是执行了我们的get方法打印了"触发了get方法--->"

三.CBV加装饰器

  • 可以给类添加装饰器
  • 可以在方法上添加装饰器
from django.views import View
from django.utils.decorators import method_decorator

# 第一种写法:直接加在类上
# 第一个参数是装饰器引用,第二个参数是被装饰对象的方法
# @method_decorator(auth,name='get')
class MyViews(View):
    # 第二种写法:指名道姓的加在方法上(不需要指定方法名name)
    @method_decorator(auth)
    def get(self, request, *args, **kwargs):
        return HttpResponse('触发get')

    def post(self, request, *args, **kwargs):
        return HttpResponse('触发post')

版权声明:
作者:淘小欣
链接:https://blog.taoxiaoxin.club/159.html
来源:淘小欣的博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
Django FBV与CBV,CBV源码剖析
一、FBV与CBV 1.FBV基于函数的视图(Function base view) 之前我们在视图层都用的是基于函数的视图,使用函数来处理不同的请求。 基于视图的函数我们学习Dj……
<<上一篇
下一篇>>