DRF:如何通过中间件正确更新继承默认User的Profile模型?
问题分析与解决方案
我一眼就看到问题出在update_or_create的调用方式上——你没给它指定查找匹配的条件,它根本不知道要对应哪个用户的Profile记录!下面一步步帮你修正:
第一步:修正中间件的核心逻辑
你的中间件里,update_or_create的用法完全错了。这个方法需要先传入用于定位现有记录的条件,再通过defaults参数指定要更新的字段。把middleware.py改成这样:
from django.utils import timezone class UpdateLastActivityMiddleware(object): def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # 把更新逻辑放在请求处理完成后执行,更贴合"最后活动时间"的语义 if request.user.is_authenticated: # 正确用法:先指定查找条件,再用defaults传要更新的字段 Profile.objects.update_or_create( user=request.user, # 核心:绑定当前登录用户 defaults={'last_activity': timezone.now()} ) return response # 可以删掉process_view方法,我们把逻辑移到__call__里更合理
关键说明:
user=request.user是核心:告诉Django要找当前登录用户对应的Profile,找不到就自动创建一条和该用户绑定的新记录。defaults参数:专门用来存放要更新/设置的字段,避免和查找条件混淆。- 移到
__call__的响应阶段:不会在视图处理前就执行更新,等请求完成后再更新,更符合业务逻辑。
第二步:可选但强烈推荐的优化——用信号自动生成Profile
为了避免新用户注册后没有Profile记录的情况,建议在models.py里添加Django信号,让User创建时自动生成对应Profile:
from django.db.models.signals import post_save from django.dispatch import receiver from django.contrib.auth.models import User from django.utils import timezone class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) last_activity = models.DateTimeField() # filled in by middleware def __str__(self): return str(self.id) # 新用户创建时自动生成Profile @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance, last_activity=timezone.now()) # 保存User时同步保存Profile @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): instance.profile.save()
这样新用户注册后,系统会自动为他生成Profile,中间件只需要负责更新last_activity字段即可。
验证修改效果
- 重启Django服务器
- 用已注册用户登录并发送任意请求
- 访问你的
ProfileList接口,就能看到该用户的Profile记录,且last_activity字段已经被正确更新
内容的提问来源于stack exchange,提问作者venv
相关产品推荐
相关产品推荐

