Django 1.9.2 "обратная" ошибка при попытке сброса пароля

Мое приложение работает на Django 1.9.2 и Django REST Framework 3.3.2 с одностраничным приложением на внешнем интерфейсе. Я должен признать, что я новичок в Django, но документы не имеют себе равных.

Я пытаюсь реализовать пользовательское представление PasswordResetForm. Моя стратегия заключается в следующем:

  1. Пользователь использует в интерфейсной форме, что POSTданные (email строка) до конечной точки API (api/v1/password/reset) когда она хочет сбросить свой пароль.
  2. Если электронная почта найдена в БД, отправьте электронное письмо и верните успешный ответ.

Для части 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 ответа

Решение

В URL в вашем HTML вы передаете token и uidb64:

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

Однако в вашем фактическом URL вы не ссылаетесь на token или же uidb64:

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

Я бы порекомендовал изменить ваш URL на:

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')

Ваш URL назван password-reset-link не поддерживает ключевые аргументы uidb64 а также token что вы отправляете это. Эти ключевые аргументы не просто дополнительные данные, они должны совпадать где-то в шаблоне URL.

Согласно ошибке, ваш шаблон URL:

api/v1/password/reset/?$

Чтобы поддержать то, что вы хотите, вам нужно поместить два именованных аргумента <uidb64> а также <token>, Например:

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

Вам нужно настроить регулярное выражение для поддержки форматов uidb64 и token.

Другие вопросы по тегам