Django 1.9.2"反向"密码重置尝试期间出错

时间:2016-10-18 14:29:39

标签: django django-rest-framework django-email

我的应用程序位于Django 1.9.2和Django REST Framework 3.3.2上,前端有一个页面应用程序。我必须承认我是Django的新手,但文档是无与伦比的。

我正在尝试实现自定义PasswordResetForm视图。我的策略如下:

  1. 当用户想要重置密码时,用户在POST数据(email字符串)的前端表单上使用API​​端点(api/v1/password/reset)。
  2. 如果在数据库中找到电子邮件,请发送电子邮件并返回成功的回复。
  3. 对于第1部分,请参阅相关代码:

    # urls.py
    
    url(r'^api/v1/password/reset/?$', PasswordResetView.as_view(), name='password-reset-link')
    

    -

    # views.py
    
    class PasswordResetView(GenericAPIView):
        serializer_class = PasswordResetSerializer
        permission_classes = (AllowAny,)
    
        def post(self, request, *args, **kwargs):
            # Use DRF serializer to validate data.
            serializer = self.get_serializer(data=request.data)
    
            # Ensure data is valid before proceeding.
            if serializer.is_valid() == False:
                return Response('error': serializer.errors, 'message': 'Error while attempting to reset password'}, status.HTTP_400_BAD_REQUEST)
    
            else:
                # Ensure the user exists.
                existing_user = get_user_model().objects.filter(
                    email=serializer.validated_data.get('email')
                )
    
                if not existing_user:
                    return Response({'error': {'code': 'email_not_in_db'}}, status.HTTP_404_NOT_FOUND)
    
            # Validated data fed to a child class of PasswordResetForm.
            form = UserForgotPasswordForm(serializer.validated_data)
    
            if form.is_valid():
                path = os.path.join(os.path.dirname(os.path.abspath(__file__ + '../../')), 'templates/registration/password_reset_email.html')
    
                try:
                    # Save form, effectively attempting to trigger mail sending. 
                    # Unfortunately an exception gets thrown!
                    form.save(from_email='no-reply@abc.xyz', email_template_name=path, request=request)
    
                    return Response({'message': 'Password reset request sent'}, status=status.HTTP_200_OK)
    
                except Exception as e:
                    return Response({'error': str(e), 'message': 'Error while attempting to reset password'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    

    -

    # forms.py
    
    class UserForgotPasswordForm(PasswordResetForm):
        email = forms.EmailField(required=True, max_length=254)
    
        class Meta:
            model = CustomUser
            fields = ('email',)
    

    -

    # my_app/templates/registration/password_reset_email.html
    
    {% load i18n %}{% autoescape off %}
    {% blocktrans %}You're receiving this email because you requested a password reset for your user account.{% endblocktrans %}
    
    {% trans "Please go to the following page and choose a new password:" %}
    {% block reset_link %}
    {{ protocol }}://{{ domain }}{% url 'password-reset-link' uidb64=uid token=token %}
    {% endblock %}
    {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
    
    {% endautoescape %}
    

    -

    但是我收到以下错误:

    Reverse for 'password-reset-link' with arguments '()' and keyword arguments '{'uidb64': b'MTI1', 'token': '4g9-f370fd6ee48d90a40b67'}' not found. 1 pattern(s) tried: ['api/v1/password/reset/?$']
    

    知道为什么吗?我错过了什么?谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

在您的HTML中的网址中,您传递了tokenuidb64

{{ protocol }}://{{ domain }}{% url 'password-reset-link' uidb64=uid token=token %}

但是,在您的实际网址中,您没有引用tokenuidb64

url(r'^api/v1/password/reset/?$', PasswordResetView.as_view(), name='password-reset-link')

我建议您将网址更改为:

url(r'^api/v1/password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', PasswordResetView.as_view(), name='password-reset-link')

答案 1 :(得分:1)

您的名为password-reset-link的网址不支持您发送的关键字参数uidb64token。这些关键字参数不仅仅是额外的数据,它们需要匹配URL模式中的某个位置。

根据错误,您的网址格式为:

api/v1/password/reset/?$

为了支持您想要的内容,您需要将两个named arguments称为<uidb64><token>。例如:

api/v1/password/reset/(?P<uidb64>[a-zA-Z0-9]+)/(?P<token>[a-zA-Z0-9]+)/?$

您必须调整正则表达式以支持uidb64和令牌格式。