fbv中request对象全程不变,仅属性可能被修改;cbv中dispatch()前完成setup()并绑定request等属性,确保self.request可用。

FBV 函数视图里 request 对象什么时候会变?
函数视图(def 写的视图)本身没有生命周期管理,request 就是调用时传进来的那个对象,全程不变。但容易踩的坑是:你在中间件、装饰器或 request.session 操作后误以为它“更新了”,其实只是它的属性被改了——比如 request.user 是懒加载的,首次访问才触发认证逻辑,之前一直是 AnonymousUser。
- 装饰器如
@login_required不会替换request,只可能提前返回HttpResponse -
request.POST和request.GET是QueryDict,可变;但修改它们不会影响后续中间件行为(因为中间件在视图前已执行完) - 别在函数里反复调用
request.user.is_authenticated——第一次访问已触发认证,后面是缓存值
CBV 类视图的 dispatch() 到 get()/post() 之间发生了什么?
dispatch() 是 CBV 的入口闸门,它根据 request.method 转发到对应方法(get、post 等),但在这之前,Django 已完成几件事:检查 http_method_names 白名单、运行 setup()(Django 3.1+)、把 request、args、kwargs 绑定为实例属性(所以你在 get() 里能直接用 self.request)。
- 自定义
dispatch()时,必须显式调用return super().dispatch(request, *args, **kwargs),否则不会走到get()/post() -
setup()在dispatch()开头立即执行,适合初始化实例变量(比如self.object = None),比在__init__里做更安全(此时request已就位) - 如果重写了
http_method_not_allowed,它只在dispatch()找不到对应方法时触发,不是 405 的唯一来源(中间件也可能提前拦截)
FBV 和 CBV 在中间件执行顺序上真的一样吗?
完全一样。Django 的中间件链不区分视图类型,都是 process_request → process_view → 视图执行 → process_response。关键差异在 process_view 阶段:它收到的是视图函数对象(FBV)或类的 view_func(CBV 的 as_view() 返回的闭包),所以你没法靠中间件判断“当前是类还是函数”——除非检查 view_func.__name__ 是否含 "View" 或看 view_func.__qualname__。
-
process_view的view_func参数对 FBV 是原函数,对 CBV 是ViewClass.as_view().view_class返回的内部函数,本质仍是函数 - 想统一加权限逻辑?别在中间件里硬判类型,用
@method_decorator包 CBV,或给 FBV 加装饰器,语义更清晰 - 性能上无差别,但 CBV 因多一层方法分发,调用栈略深(微秒级,不用优化)
为什么 CBV 的 setup() 和 __init__() 容易混淆?
__init__() 在每次请求来时被调用,但此时 request 还没传进来(as_view() 返回的是个闭包,真正实例化在 dispatch() 里);而 setup() 是 Django 3.1 引入的钩子,在 dispatch() 开头、request 已绑定后立即执行,这才是你该放初始化逻辑的地方。
- 在
__init__()里访问self.request会报AttributeError——它根本不存在 -
setup()是唯一保证self.request、self.args、self.kwargs都就位的钩子 - 旧项目升级到 Django 3.1+ 后,把原来写在
dispatch()开头的初始化代码移到setup()更规范
self.xxx),但这个状态仅存活于单次请求周期内——很多人误以为可以跨请求复用 self 属性,其实每次请求都是全新实例。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











