Django——CBV源码解析

Django------CBV源码解析

以下是views模块调用as_view()方法的代码示例

python 复制代码
# urls.py
from django.contrib import admin
from django.urls import path
import app.views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app/', app.views.task.as_view()),
]
python 复制代码
# views.py
class task(View):
    # 根据id获取
    def get(self, request, u_id):
        response = {'code': '200', 'msg': "查询成功"}
        return JsonResponse(json.dumps(response), safe=False)

该功能实现的是当有get请求发送到app这个接口时会返回一个response字典

首先引入问题:为什么浏览器向后端发送get请求时会被该get方法精准接受?

其实是因为在注册url时app.views调用的as_view()方法帮我们做好了大部分规划

Ctrl+左键进入as_view()源码

python 复制代码
class View:
    http_method_names = [
        "get",
        "post",
        "put",
        "patch",
        "delete",
        "head",
        "options",
        "trace",
    ]

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)


    @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(
                    "The method name %s is not accepted as a keyword argument "
                    "to %s()." % (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)
            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

        # __name__ and __qualname__ are intentionally left unchanged as
        # view_class should be used to robustly determine the name of the view
        # instead.
        view.__doc__ = cls.__doc__
        view.__module__ = cls.__module__
        view.__annotations__ = cls.dispatch.__annotations__
        # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
        # the dispatch method.
        view.__dict__.update(cls.dispatch.__dict__)

        # Mark the callback if the view class is async.
        if cls.view_is_async:
            markcoroutinefunction(view)

        return view


    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)

    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},
        )
        response = HttpResponseNotAllowed(self._allowed_methods())

        if self.view_is_async:

            async def func():
                return response

            return func()
        else:
            return response
  • @classonlymethod表示只能用类调用此方法,这也是为什么我们只能用as_views()而不是as_views
  • 这个时候我们来到了task(View)继承的View类下的as_view()方法
  • 中间的步骤先不管 直接看return view
python 复制代码
def view(request, *args, **kwargs):
    self = cls(**initkwargs)
    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方法
  • 这里的request参数就是我们的浏览器接受的request请求,如果没填request则会弹出一个error
  • 重点是最后调用了实例中的dispatch方法
  • 既然我们的task类调用了dispatch方法那么就应该在task类下搜寻这个方法,但是很明显我们没有写过这方法,因此又回到父类View中的dispatch方法(这俩方法挨得很近,往下翻翻就找到了)
python 复制代码
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)
  • if request.method.lower() in self.http_method_names:当我们的request请求类型存在于http_method_names
  • 那么先看看这个http_method_names是什么东西
python 复制代码
http_method_names = [
    "get",
    "post",
    "put",
    "patch",
    "delete",
    "head",
    "options",
    "trace",
]
  • 其实就是个定义好的字符串列表
  • 再接着看dispatch
python 复制代码
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
  • 其实就是从我们task实例中获取相应的HTTP请求方法,如果不存在就用它默认的
  • 最后返回handler,再解释一下gatter的用法
python 复制代码
class Test(object):
    x = 1


a = Test()
print(getattr(a, 'x'))  # 获取属性 x 值
# 结果:1
print(getattr(a, 'y', 'None'))  # 获取属性 y 值不存在,但设置了默认值
# 结果:None
print(a.x)  # 效果等同于上面
# 结果:1
  • 回到我们最初的问题为什么浏览器向后端发送get请求时会被该get方法精准接受?
  • 走到这里基本可以得出结论了,说白了就是如果我有get就走我类下的get方法,没有就走它默认的
相关推荐
子燕若水1 小时前
uv 安装包
开发语言·chrome·python
weixin_307779131 小时前
Python获取能唯一确定一棵给定的树的最少数量的拓扑序列
数据结构·python
A.sir啊2 小时前
爬虫基础(六)代理简述
爬虫·python·网络协议
weixin_307779132 小时前
PySPARK带多组参数和标签的SparkSQL批量数据导出到S3的程序
大数据·数据仓库·python·sql·spark
Hi Man3 小时前
Python之如何在Visual Studio Code 中写的python程序打包成可以在Windows系统下运行的.exe程序
开发语言·vscode·python
Return-Log3 小时前
Matplotlab显示OpenCV读取到的图像
python·opencv
程序趣谈3 小时前
算法随笔_36: 复写零
数据结构·python·算法
九亿AI算法优化工作室&4 小时前
GWO优化LSBooST回归预测matlab
人工智能·python·算法·机器学习·matlab·数据挖掘·回归
weixin_307779134 小时前
在AWS上使用Flume搜集分布在不同EC2实例上的应用程序日志具体流程和代码
python·flask·云计算·flume·aws
sirius123451235 小时前
自定义数据集 ,使用朴素贝叶斯对其进行分类
python·分类·numpy