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方法,没有就走它默认的
相关推荐
空心木偶☜8 分钟前
A2A2A(多智能体协作)
开发语言·python·ai·ai编程
Cc.Y10 分钟前
Java零基础入门:类与对象深度掌握 —— 从“零散变量“到“打包管理“
java·开发语言·python
AINative软件工程21 分钟前
LLM Prompt Registry 工程实践:集中管理 Prompt,让模型调用不再散落在代码各处
后端·python·llm
Patrick在香港29 分钟前
MCP 的 initialize 握手真的没了?67 行标准库实测 2026-07-28 规范
python·agent·claude·mcp·json-rpc
vx_Biye_Design32 分钟前
springboot角色扮演服务平台65161-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计
追烽少年x34 分钟前
从零构建一个3D点云预览器:Python + PySide6 + pyqtgraph 实战
python·3d
weixin_440401691 小时前
质朴的爬虫+数据处理
爬虫·python·数据分析·pandas
估值探索者1 小时前
【Python量化系统工程实战 #01】数据存储选型 CSVSQLiteMySQL 对比与 SQLite 实战建库
开发语言·jvm·python·sqlite·api接口·数据api接口·股票数据api接口
计算机毕业编程指导师1 小时前
计算机毕设答辩技巧:基于Hadoop+Django的公共交通运营数据分析与可视化系统怎么做 源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·spark·毕业设计·课程设计·交通运行
砚底藏山河1 小时前
量化实战:行情数据 Schema 演进与向后兼容
java·python·金融·maven