Django 1.6.5 中 URL 重置密码的问题和解决方案

98 阅读2分钟

在使用 Django 1.6.5 中的 django.contrib.auth.views.password_reset 进行用户密码重置时,可能会遇到以下错误:

NoReverseMatch at /reset/Nw/3u5-5654a2cadfa432b86577/
Reverse for 'password_reset_complete' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []

或者,当在 URL 中添加参数 name='password_reset_confirm' 时,可能会遇到以下错误:

A server error occurred. Please contact the administrator.

2、解决方案

要解决这些错误,需要进行以下修改:

  1. 在 URL 配置中,将 'django.contrib.auth.views.password_reset_confirm' 的参数 name='password_reset_confirm' 从 URL 中删除:

    (r'^reset/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>.+)/$',
     'django.contrib.auth.views.password_reset_confirm'),
    
  2. 在视图函数中,将 password_reset_complete 的参数 name='password_reset_complete' 从 URL 中删除:

    def password_reset_complete(request, reset_uidb64=None, token=None):
        """
        Reset password complete.
        """
        redirect_to = reverse('home')
        return password_reset_complete(request,
                                        extra_context={'redirect_to': redirect_to})
    

这样,就可以解决 NoReverseMatch 和服务器错误的问题。

代码例子

以下是一个完整的代码例子,展示了如何使用 Django 1.6.5 重置用户密码:

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import (
    PasswordResetForm,
    SetPasswordForm,
)
from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.views import (
    password_change,
    password_reset,
    password_reset_confirm,
    password_reset_done,
)
from django.core.mail import send_mail
from django.shortcuts import redirect, render


def password_reset_request(request):
    """
    Reset password request.
    """
    if request.method == 'POST':
        form = PasswordResetForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            user = User.objects.filter(email=email).first()
            if user is not None:
                token = default_token_generator.make_token(user)
                send_mail(
                    'Password reset',
                    'Click here to reset your password: {}?uidb64={}&token={}'.format(
                        request.build_absolute_uri(reverse('password_reset_confirm')),
                        user.pk,
                        token)
                    from_email='noreply@example.com',
                    recipient_list=[email])
            messages.success(request, 'An email has been sent to your email address.')
            return redirect('home')
    else:
        form = PasswordResetForm()

    return render(request, 'registration/password_reset_form.html', {'form': form})


def password_reset_done(request):
    """
    Reset password done.
    """
    return render(request, 'registration/password_reset_done.html')


def password_reset_confirm(request, uidb64=None, token=None):
    """
    Reset password confirm.
    """
    if uidb64 is not None and token is not None:
        user = User.objects.get(pk=uidb64)
        if default_token_generator.check_token(user, token):
            return render(request, 'registration/password_reset_confirm_form.html', {'uidb64': uidb64, 'token': token})
    return redirect('home')


def password_reset_complete(request):
    """
    Reset password complete.
    """
    redirect_to = reverse('home')
    return password_reset_complete(request,
                                   extra_context={'redirect_to': redirect_to})


@login_required
def change_password(request):
    """
    Change password.
    """
    if request.method == 'POST':
        form = SetPasswordForm(request.user, request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Your password has been changed.')
            return redirect('home')
    else:
        form = SetPasswordForm(request.user)

    return render(request, 'registration/change_password.html', {'form': form})

在上面的代码中,我们使用了 Django 内置的 PasswordResetFormSetPasswordForm 来处理密码重置和修改,并使用了内置的视图函数来处理密码重置请求、完成密码重置、确认密码重置和修改密码。