Django 1.9.2 "обратная" ошибка при попытке сброса пароля
Мое приложение работает на Django 1.9.2 и Django REST Framework 3.3.2 с одностраничным приложением на внешнем интерфейсе. Я должен признать, что я новичок в Django, но документы не имеют себе равных.
Я пытаюсь реализовать пользовательское представление PasswordResetForm. Моя стратегия заключается в следующем:
- Пользователь использует в интерфейсной форме, что
POST
данные (email
строка) до конечной точки API (api/v1/password/reset
) когда она хочет сбросить свой пароль. - Если электронная почта найдена в БД, отправьте электронное письмо и верните успешный ответ.
Для части 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.