为何Django原生视图与ModelViewSet中的request对象不一致?
为什么Django原生视图和DRF ModelViewSet的request对象存在差异?
嘿,这个问题我之前在项目里也踩过坑,其实核心原因是Django原生视图和DRF视图的request对象体系完全独立,具体可以从这几个方面拆解:
1. Request对象的类型不一样
- 原生Django视图接收的是
django.http.HttpRequest实例,它的user属性是由Django自带的认证中间件(比如django.contrib.auth.middleware.AuthenticationMiddleware)填充的,默认依赖session/cookie来识别用户。 - DRF的ModelViewSet等视图接收的是
rest_framework.request.Request实例——这是DRF对原生HttpRequest的封装,它的user属性由DRF专属的认证类来处理,和Django原生的认证中间件不直接挂钩。
2. 认证流程完全独立
你用的Django rest-framework Social Oauth2是DRF的认证插件,它只会在DRF的视图流程里生效:
当请求进入DRF视图时,DRF会依次调用
settings.py中REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES']配置的认证类,解析请求里的OAuth2 token,验证通过后才会把用户赋值给request.user。
而原生Django视图根本不会触发DRF的这套认证流程,它只会走Django原生的认证逻辑。你在浏览器里访问原生视图能看到用户已登录,大概率是因为浏览器里保存了Django的session cookie,原生中间件识别到了这个session,但这套逻辑DRF默认是不启用的。
3. 怎么让两者的用户状态保持一致?
如果想让DRF的ModelViewSet也能识别浏览器的session登录状态(比如在调试时更方便),可以在DRF配置里添加Session认证:
# settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_social_oauth2.authentication.SocialAuthentication', 'rest_framework.authentication.SessionAuthentication', # 添加这一行 ], }
反过来,如果想让原生视图也能识别OAuth2 token,就得手动在原生视图里调用DRF的认证流程,比如:
from django.http import HttpResponse from rest_framework.request import Request from rest_framework.authentication import get_authenticators from rest_framework import exceptions def index(request): # 把原生request包装成DRF Request drf_request = Request(request) # 执行DRF的认证逻辑 for authenticator in get_authenticators(drf_request): try: user_auth_tuple = authenticator.authenticate(drf_request) except exceptions.APIException: continue if user_auth_tuple: drf_request.user, drf_request.auth = user_auth_tuple break return HttpResponse( f"原生视图user匿名状态: {request.user.is_anonymous}\n" f"DRF处理后user匿名状态: {drf_request.user.is_anonymous}" )
内容的提问来源于stack exchange,提问作者SugarMouse
相关产品推荐
相关产品推荐

