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)