rest_framework(1)CBV (基于类的视图)源码解析

面向对象和反射的一些补充说明

class Animal:
    def __init__(self, name, age, func_str):
        self.name = name
        self.age = age
        # self 指的是类实例对象,此处指的是 Dog 的实例对象
        # 所以如果 Dog 中重写了 sleep 方法,那么 self.sleep() 调用的就是 Dog 中的 sleep 方法
        # 如果 Dog 中没有重写, self.sleep() 调用的才是 Animal 中的 sleep 方法
        self.sleep()

        # 反射
        # func 为 func_str 对应的方法
        # 如 func_str = "sleep", 那么 getattr 返回的就是 sleep 方法
        # 即 func = sleep
        func = getattr(self, func_str)  # => self.func_str
        func()  # 调用方法

    def sleep(self):
        print("sleep....")

    def eat(self):
        print("eat...")


class Dog(Animal):
    def sleep(self):
        print(f"{self.name} sleep....")


dog = Dog("旺财", 2, "sleep")

CBV 的简单使用

views.py 文件代码

# views.py 文件

from django.views import View
# CBV: 基于类的视图
class BookView(View):
    # 当前段发送 GET 请求时,会执行 get 方法,方法名为对应的请求类型,不能随便修改
    def get(self, request):
        return HttpResponse("GET 请求....")

    # 当前段发送 POST 请求时,会执行 post 方法
    def post(self, request):
        return HttpResponse("POST 请求...")

    # 当前段发送 DELETE 请求时,会执行 delete 方法
    def delete(self, request):
        return HttpResponse("DELETE 请求....")

 urls.py 文件代码

# urls.py 文件

from .views import BookView

urlpatterns = [
    path('book/', BookView.as_view()),
}

对 urls.py 文件中的 BookView.as_view() 进行分析

BookView.as_view() 最终指的是 django.views.View 中的 as_view()。

as_view() 源码如下,也就是说调用 as_view() 方法,最终会返回一个 view 方法,所以 django 启动时, 执行语句 BookView.as_view() 得到一个方法 view , 即 path('book/', BookView.as_view())  =>  path('book/', view) 。由此可以看出 CBV 的本质还是 FBV (基于函数的视图)。

# as_view() 源码解读
as_view() 方法是在 django.views.View 中
as_view() 源码的关键部分如下:

@classonlymethod
def as_view(cls, **initkwargs):
    # do something....

    def view(request, *args, **kwargs):
            # do something....

    # do something....

    return view

当用户以 get 请求(或者其他请求)访问  “/book/” 时,就会执行 view() 方法,即 get 请求访问 /book/  =>  view()  =>  dispatch()

对 as_view() 方法中的 view() 方法进行分析

@classonlymethod
def as_view(cls, **initkwargs):
    # do something...
    def view(request, *args, **kwargs):
        # cls 指向 BookView 类,因为是 BookView 调用的 as_view()
        # 创建一个 BookView 类实例对象,此处等价于 self = Bookview(**initkwargs)
        self = cls(**initkwargs)
        self.setup(request, *args, **kwargs)

        # do something...
        
        # self.dispatch() 先去 BookView 类中查找 dispatch 方法
        # 如果找不到,再找 BookView 父类,即 View
        # 所以 self.dispatch() 访问的是 View 中的 dispatch 方法
        return self.dispatch(request, *args, **kwargs)

    # do something...

    return view

对 django.views.View 类中的 dispatch() 方法进行分析

所以当用户以 get 请求(或者其他请求)访问  “/book/” 时,就会执行 view() 方法,即 get 请求访问 /book/  =>  view()  =>  dispatch()  =>  handler()  =>  get(),即 BookView 中的 get()  =>  get() 方法中 return HttpResponse("GET 请求....")

而如果用户以 post 请求(或者其他请求)访问  “/book/” 时,也会执行 view() 方法,即 post 请求访问 /book/  =>  view()  =>  dispatch()  =>  handler()  => post(),即 BookView 中的 post()  =>  post() 方法中 return HttpResponse("POST 请求....")

所以 dispatch 称为分发,因为不管前端发送什么请求,最后都会通过 dispatch 分发到对应的视图函数中,执行相应的逻辑。

def dispatch(self, request, *args, **kwargs):
    """
        下面的 if-else 的核心就是:
        handler = getattr(self, request.method.lower())
        即文章开头提到的反射:handler = self.request.method.lower()
        现假设以 get 请求访问 /book/, 则代码变为
        handler = self.get
        此处的 self 是 BookView 类的实例对象
        所以 handler 为 BookView 类中的 get 方法
        对应上了 BookView 类中定义的 get
    """

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

    """
        如果请求方法不在允许的列表里,或者 self 实例对象中没有改请求方法
        则 handler = self.http_method_not_allowed
        即执行不允许的请求方法
    """
    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

    # 调用 handler(),并将其方法调用后的结果返回
    return handler(request, *args, **kwar
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值