django NoReverseMatch at /reset-password-confirm/

h7wcgrx3  于 2023-10-21  发布在  Go
关注(0)|答案(1)|浏览(95)

我试图通过使用View类实现重置密码视图。实际上,我遇到了一个令人讨厌的错误。
我有三个实施意见:

  1. UserResetPasswordView在这里用户输入电子邮件并将请求发送到他/她的电子邮件
  2. UserResetPasswordRequestSentView此处显示电子邮件已发送的消息
  3. UserResetPasswordConfirm在上面的2个视图后,此视图让用户更改密码。
    在将用户重定向到UserResetPasswordRequestSentView后,将向用户的电子邮件发送一封电子邮件,以访问用户更改他/她的密码。
    因此用户将被重定向到包含用于设置新密码输入的UserResetPasswordConfirm
    以下是我的urls.py脚本:
urlpatterns = [
    path(
        route='reset-password',
        view=views.UserResetPasswordView.as_view(),
        name='reset',
    ),
    
    path(
        route='reset-password-request-sent',
        view=views.UserResetPasswordRequestSentView.as_view(),
        name='reset_sent',
    ),
    
    path(
        route='reset-password-confirm/<uidb64>/<token>',
        view=views.UserResetPasswordConfirm.as_view(),
        name='reset_confirm',
    ),
]

这是UserResetPasswordView视图:

class UserResetPasswordView(View):
    def get(self, request: HttpRequest) -> HttpResponse:
        reset_password_form: ResetPasswordForm = ResetPasswordForm()
        return render(
            request=request,
            template_name='reset/reset.html',
            context={
                'reset_password_form': reset_password_form,
            },
        )
        
    def post(self, request: HttpRequest) -> Union[HttpResponseRedirect, HttpResponsePermanentRedirect, HttpResponse]:
        reset_password_form: ResetPasswordForm = ResetPasswordForm(request.POST or None)
        if (reset_password_form.is_valid()):
            cd = reset_password_form.cleaned_data
            user = get_user_model().objects.filter(Q(email=cd['email'])).first()
            if (user):
                subject = 'درخواست بازنشانی رمز ورود'
                message = render_to_string(
                    template_name='email/template_reset_password.html',
                    context={
                        'user': user,
                        'domain': get_current_site(request=request).domain,
                        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                        'token': account_activation_token.make_token(user),
                        'protocol': 'https' if request.is_secure() else 'http',
                    }
                )
                send_mail(
                    subject,
                    message,
                    'settings.EMAIL_HOST_USER',
                    [cd['email']],
                    fail_silently=False
                )
                return redirect(to=reverse('reset_sent'))
            else:
                return redirect(to=reverse('reset'))
        
        return render(
            request=request,
            template_name='reset/reset.html',
            context={
                'reset_password_form': reset_password_form,
            },
        )

这是用户可以设置新密码的表单(UserResetPasswordConfirm):

class UserResetPasswordConfirm(View):
    def get(self, request: HttpRequest, uidb64, token) -> HttpResponse:
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user_obj = User.objects.get(pk=uid)
        except:
            user_obj = None
        if (user_obj is not None and account_activation_token.check_token(user_obj, token)):
            form: ResetPasswordConfirmForm = ResetPasswordConfirmForm()
        else:
            messages.error(
                request=request,
                message='توکن شما منقضی شده است',
            )
        return render(
            request=request,
            template_name='reset/reset-confirm.html',
            context={
                'form': form,
            },
        )
    
    def post(self, request: HttpRequest, uidb64, token) -> Union[HttpResponseRedirect, HttpResponsePermanentRedirect, HttpResponse]:
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user_obj = User.objects.get(pk=uid)
        except:
            user_obj = None
        if (user_obj is not None and account_activation_token.check_token(user_obj, token)):
            form: ResetPasswordConfirmForm = ResetPasswordConfirmForm(request.POST or None)
            if (form.is_valid()):
                cd = form.cleaned_data
                if (cd['new_password'] != cd['con_new_password']):
                    form.add_error(
                        field='new_password',
                        error='رمز ورود شما با یکدیگر مطابقت ندارد',
                    )
                else:
                    user_obj.set_password(raw_password=cd['new_password'])
                    user_obj.save()
                    return redirect(to=reverse('reset_complete'))
            else:
                form.add_error(
                    field='new_password',
                    error='رمز ورود شما با یکدیگر مطابقت ندارد',
                )
            return render(
                request=request,
                template_name='reset/reset-confirm.html',
                context={
                    'form': form,
                },
            )
        else:
            messages.error(
                request=request,
                message='توکن شما منقضی شده است',
            )
        return render(
            request=request,
            template_name='reset/reset-confirm.html',
            context={
                'form': form,
            },
        )

这是form,包含为用户设置新密码的输入:

{% extends "base.html" %}
{% load static %}
{% block title %}
    <title>
        تنظیم رمز ورود جدید
    </title>
{% endblock %}
{% block body %}
    <div class="container text-center mt-5">
        <form class="form-inline" action="{% url 'reset_confirm' %}" method="post">
            {% csrf_token %}
            <div class="row">
                <h6 class="text-info mt-2">رمز ورود جدید حداقل بین 8 تا 64 کاراکتر (ترکیب حروف و اعداد)</h6>
                <div class="field">
                    <p class="control has-icons-left">
                        {{ form.new_password }}
                        <span class="icon is-small is-left">
                            <i style="color: #1F2330;" class="fas fa-lock"></i>
                        </span>
                    </p>
                </div>
                <h6 class="text-info mt-2">تایید مجدد رمز ورود جدید</h6>
                <div class="field">
                    <p class="control has-icons-left">
                        {{ form.con_new_password }}
                        <span class="icon is-small is-left">
                            <i style="color: #1F2330;" class="fas fa-lock"></i>
                        </span>
                    </p>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <button style="width: 150px;" id="set_pass" type="submit" class="btn btn-info text-dark">ارسال درخواست</button>
                </div>
            </div>
        </form>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
        jQuery(function($){
            $(document).ajaxSend(function() {
                $('spinner-border').fadeIn(580);

                var loading_tag = '<div class="spinner-border"></div>&nbsp;&nbspلطفا صبر کنید';
                $('#set_pass').html(loading_tag);
            });

            $('#set_pass').click(function() {
                $.ajax({
                    type: 'GET',
                    success: function(data) {
                        console.log(data);
                    }
                }).done(function() {
                    setTimeout(function() {
                        $('.spinner-border').fadeOut(500);
                    }, 700);
                });
            });
        });
    </script>
{% endblock %}

在这里,用户应该打开通过电子邮件发送的链接,但每次我试图将用户重定向到UserResetPasswordConfirm,django都会显示此错误:

如果你能帮助我,我将非常感激。

jecbmhm3

jecbmhm31#

使用uidb64token渲染 *,因此:

class UserResetPasswordConfirm(View):
    def get(self, request: HttpRequest, uidb64, token) -> HttpResponse:
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user_obj = User.objects.get(pk=uid)
        except:
            user_obj = None
        if user_obj is not None and account_activation_token.check_token(
            user_obj, token
        ):
            form: ResetPasswordConfirmForm = ResetPasswordConfirmForm()
        else:
            messages.error(request=request, message='توکن شما منقضی شده است')
        return render(
            request=request,
            template_name='reset/reset-confirm.html',
            context={'form': form, 'uidb64': uidb64, 'token': token},
        )

    # …

然后在视图中使用这些来确定URL:

<form class="form-inline" action="{% url 'reset_confirm' uidb64 token %}" method="post">

注意redirect(…) [Django-doc]通常会使用视图的名称和kwargs(可选),所以不要使用**reverse(…)[Django-doc]。因此,您可能需要将redirect(redirect('reset_complete'))重写为redirect('reset_complete')
注意:直接子类化View类通常是 * 不 * 必要的。在这种情况下,你的视图看起来像一个
FormView**[Django-doc]。通过使用FormView而不是简单的View,您通常不必实现大量样板代码。

相关问题