Django 类视图(CBV)源码级解析 ——从浏览器敲下回车到真正执行 `get()` / `post()` 的全过程
Django 类视图(CBV)源码级解析
——从浏览器敲下回车到真正执行 get()
/ post()
的全过程
一、as_view()
:类方法返回真正的「视图函数」
django/views/generic/base.py View 类
# django/views/generic/base.py View 类
@classonlymethod
def as_view(cls, **initkwargs):
"""
入口:urls.py 里写的 LoginView.as_view()
返回值是一个闭包 view——也就是 Django 最终调用的「视图函数」。
"""
# 省略若干参数检查 …
def view(request, *args, **kwargs):
# 1. 实例化当前类 cls(**initkwargs) => LoginView()
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
# 2. 把 request、*args、**kwargs 挂到实例上
if not hasattr(self, 'request'):
raise AttributeError("…")
# 3. 进入「分发」逻辑
return self.dispatch(request, *args, **kwargs)
# 4. 给闭包加一些元数据,方便调试
view.view_class = cls
view.view_initkwargs = initkwargs
return view # ← urls.py 真正拿到的就是这个 view
-
实例化当前类 cls(**initkwargs) => LoginView()
-
把 request、*args、**kwargs 挂到实例上
-
进入「分发」逻辑
-
给闭包加一些元数据,方便调试
要点:
-
as_view()
带括号是因为要 立即执行 并返回闭包view
。 -
闭包内部把
cls
(例如LoginView
)实例化成self
,后面所有逻辑都围绕这个实例展开。
那我们再看看dispatch()
方法做了什么
二、dispatch()
:HTTP 方法的分发器
# 仍在 View 类中
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def dispatch(self, request, *args, **kwargs):
# 1. 取小写方法名
method = request.method.lower()
# 2. 判断是否在白名单
if method in self.http_method_names:
# 3. 反射:去实例上找同名方法,找不到就兜底 http_method_not_allowed
handler = getattr(self, method, self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 4. 真正执行 get() / post() / put() …
return handler(request, *args, **kwargs)
-
取小写方法名
-
判断是否在白名单
-
如果在反射:去实例上找同名方法,如果不在找不到就兜底 http_method_not_allowed
-
真正执行 get() / post() / put() …
要点:
-
405 的由来:当
method
不在http_method_names
或 子类没有实现同名方法时,handler
指向http_method_not_allowed
,返回HttpResponseNotAllowed(status=405)
。 -
反射语句
getattr(self, method, ...)
保证了LoginView.get
/LoginView.post
会被精准调用。
三、整体时序图(浏览器 → Django → 你的代码)
-
浏览器 GET /login/
-
Django 路由匹配 → 执行
LoginView.as_view()
返回的闭包view(request)
-
view
内部:
①self = LoginView()
—— 实例化
②self.dispatch(request)
—— 方法分发
③dispatch
发现request.method == 'GET'
⇒ 找到并执行self.get(request)
-
get()
返回HttpResponse
,浏览器收到 200 OK
四、常见面试追问 & 一句话答案
-
为什么必须写
.as_view()
且要带括号?
→ 它是类方法,返回真正的视图闭包;带括号才能立即执行并拿到闭包。 -
405 是哪里抛的?
→dispatch
在用getattr
查找方法时找不到,就 fallback 到http_method_not_allowed
。 -
cls
和self
各代表谁?
→cls
是类本身(LoginView),self
是本次请求实例化的 LoginView 对象。
背住以上三句话,再读 CBV 源码即可如履平地。源码阅读能让我们刨根问题,学习作者的思想,对面试也有帮助。。还有就是看源码一定不要陷进去。。
- 点赞
- 收藏
- 关注作者
评论(0)