Django 4中UserAdmin的save_model修改密码时未触发问题
解决Django后台修改用户密码时save_model不触发的问题
问题根源
Django Admin里的用户密码修改页面是独立模块,它走的是user_change_password专属视图,而非常规的模型保存流程,所以你重写的save_model方法根本不会被调用。
两种可行解决方案
方案一:重写changeform_view拦截密码修改请求
直接在自定义UserAdmin里拦截密码修改的POST请求,完成密码修改后清理用户会话:
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User from django.contrib import admin from django.contrib.auth import update_session_auth_hash from django.contrib.sessions.models import Session @admin.register(User) class UserAdmin(BaseUserAdmin): def changeform_view(self, request, object_id=None, form_url='', extra_context=None): # 判断是否是密码修改提交 if request.method == 'POST' and '_password' in request.POST: user = User.objects.get(pk=object_id) # 删除该用户的所有活跃会话 sessions = Session.objects.filter(session_data__contains=f'"_auth_user_id": "{user.pk}"') sessions.delete() # 如果修改的是当前管理员自己的密码,要更新会话哈希避免被登出 if user == request.user: update_session_auth_hash(request, user) return super().changeform_view(request, object_id, form_url, extra_context)
方案二:监听user_password_changed信号
Django在用户密码修改完成后会发送user_password_changed信号,通过监听这个信号来自动清理会话:
from django.contrib.auth.signals import user_password_changed from django.contrib.sessions.models import Session from django.dispatch import receiver @receiver(user_password_changed) def invalidate_user_sessions(sender, user, **kwargs): # 清除该用户的所有会话 sessions = Session.objects.filter(session_data__contains=f'"_auth_user_id": "{user.pk}"') sessions.delete()
把这段代码放在admin.py里即可,要是单独放signals.py,记得在apps.py的ready方法里导入信号确保生效。
注意点
- 用信号方案时,要确认信号被正确注册,别因为导入顺序问题导致没触发。
- 修改自己密码的管理员,必须调用
update_session_auth_hash,不然会被直接踢下线。
内容的提问来源于stack exchange,提问作者Mave
相关产品推荐
相关产品推荐

