如何在Django中间件中修改request.user并添加profile属性?
问题根源
你遇到的问题核心是:
- 你在Middleware中手动调用
JWTAuthentication().authenticate(request)获取用户,但DRF会在视图处理阶段再次执行认证逻辑,将request.user替换为从数据库加载的实际User实例,覆盖了你之前给request.user(此时是SimpleLazyObject懒加载对象)添加的profile属性。 SimpleLazyObject是Django用于延迟加载用户的包装器,当你给它添加属性后,一旦它被解析为真实的User实例,这些额外属性不会自动传递到新的实例上,导致视图中访问request.user.profile时触发属性不存在的错误。
解决方案:自定义JWT认证类
既然DRF会在视图阶段执行认证,我们可以直接在认证过程中给用户实例添加profile属性,确保属性伴随最终的User实例传递到视图中。
步骤1:创建自定义认证类
在users/authentication.py(无则新建)中编写:
from rest_framework_simplejwt.authentication import JWTAuthentication from users.models import User class CustomJWTAuthentication(JWTAuthentication): def authenticate(self, request): # 调用父类方法完成JWT认证,获取用户和token user, token = super().authenticate(request) if user is not None: # 从token payload中获取profile_type profile_type = token.payload.get("profile_type", None) # 给用户实例添加profile和profile_type属性 user.profile = User.get_profile(profile_type, user) user.profile_type = profile_type return user, token
步骤2:替换DRF默认认证类
修改settings.py中的REST_FRAMEWORK配置,将默认的JWT认证类替换为自定义类:
REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), "DEFAULT_RENDERER_CLASSES": ( "rest_framework.renderers.JSONRenderer", "rest_framework.renderers.BrowsableAPIRenderer", ), "DEFAULT_AUTHENTICATION_CLASSES": [ "users.authentication.CustomJWTAuthentication", # 替换为自定义类 ], }
步骤3:移除原Middleware(可选)
现在不需要原来的SetProfileMiddleware了,可以从settings.py的MIDDLEWARE中移除它,避免重复认证操作。
验证
修改后,视图中直接访问self.request.user.profile就能正常获取到对应的profile对象,不会再触发AttributeError。
内容的提问来源于stack exchange,提问作者Ravexina
相关产品推荐
相关产品推荐

