如何用自定义change_password.html替换Django Admin密码重置页并跳转登录
问题分析
从终端请求日志能看到,用户点击重置链接后访问的是 /reset/... 路径,而非你自定义的 /users/password-reset-confirm/...。原因是默认的 PasswordResetView 生成重置邮件时,用的是 Django auth 模块自带的 password_reset_confirm 命名路由(对应 /reset/ 路径),不是你在 users 应用中定义的带命名空间的路由。另外,你希望重置完成后跳转到登录页,当前配置的是跳转到 password_reset_complete,也需要调整。
解决方案
1. 自定义 PasswordResetView,生成带命名空间的重置链接
默认视图生成的链接指向 auth 模块的路由,我们需要继承 PasswordResetView,修改链接生成逻辑,指向 users 应用的重置确认路由。
在 users/views.py 中添加:
from django.contrib.auth.views import PasswordResetView from django.urls import reverse_lazy from django.utils.http import urlsafe_base64_encode from django.contrib.auth.tokens import default_token_generator from django.utils.encoding import force_bytes class CustomPasswordResetView(PasswordResetView): def get_reset_url(self, user): # 生成指向 users 应用的重置确认链接 uid = urlsafe_base64_encode(force_bytes(user.pk)) token = default_token_generator.make_token(user) return reverse_lazy('users:password_reset_confirm', kwargs={'uidb64': uid, 'token': token})
若你的 Django 版本低于 3.1(
get_reset_url是 3.1 新增方法),请改用以下代码重写send_mail:class CustomPasswordResetView(PasswordResetView): def send_mail(self, subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None): user = context['user'] uid = urlsafe_base64_encode(force_bytes(user.pk)) token = default_token_generator.make_token(user) # 替换 context 中的重置链接为带命名空间的版本 context['reset_url'] = reverse_lazy('users:password_reset_confirm', kwargs={'uidb64': uid, 'token': token}) super().send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name)
2. 更新 users/urls.py 路由配置
- 替换默认的
PasswordResetView为自定义视图 - 修改
PasswordResetConfirmView的success_url,使其跳转到登录页
修改后的 users/urls.py:
app_name = 'users' from django.contrib.auth import views as auth_views from . import views from .views import CustomPasswordResetView urlpatterns = [ path('password/', views.change_password, name='change_password'), # 使用自定义视图生成正确的重置链接 path('password-reset/', CustomPasswordResetView.as_view( template_name='users/password_reset.html', success_url=reverse_lazy('users:password_reset_done') ), name='password_reset'), path('password-reset/done/', auth_views.PasswordResetDoneView.as_view( template_name='users/password_reset_done.html' ), name='password_reset_done'), # 重置完成后跳转到登录页 path('password-reset-confirm/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view( template_name='users/change_password.html', success_url=reverse_lazy('login') ), name='password_reset_confirm'), # 若不需要重置完成提示页,可删除以下路由 path('password-reset-complete/', auth_views.PasswordResetCompleteView.as_view( template_name='users/password_reset_complete.html' ), name='password_reset_complete'), ]
3. 调整主项目 urls.py 路由顺序(可选)
将 users 应用的路由放在 django.contrib.auth.urls 之前,避免命名路由优先级冲突:
urlpatterns = [ path('admin/', admin.site.urls), path('users/', include('users.urls')), path('', include('django.contrib.auth.urls')), ]
4. 验证模板路径
确保 change_password.html 位于 users/templates/users/ 目录下,Django 能正确加载该模板。
原理说明
- 自定义
CustomPasswordResetView重写了链接生成逻辑,让邮件中的重置地址指向你自定义的路由 - 修改
PasswordResetConfirmView的success_url为login命名路由,实现重置后直接跳转登录页 - 调整主路由顺序可避免 auth 模块的默认路由优先匹配,确保自定义路由生效
内容的提问来源于stack exchange,提问作者A_K
相关产品推荐
相关产品推荐

