iMerica / dj-rest-auth

Authentication for Django Rest Framework
https://dj-rest-auth.readthedocs.io/en/latest/index.html
MIT License
1.67k stars 310 forks source link

NoReverseMatch: Reverse for 'password_reset_confirm' not found. 'password_reset_confirm' is not a valid view function or pattern name. #152

Open lukaszla opened 4 years ago

lukaszla commented 4 years ago

I'm using vanilla installation and after sending simple POST from swagger to /api/v1/dj-rest-auth/password/reset/ I get this error

ERROR [django.request:224] Internal Server Error: /api/v1/dj-rest-auth/password/reset/
Traceback (most recent call last):
  File "/web_env38/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/web_env38/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/web_env38/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/web_env38/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/web_env38/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "/web_env38/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/web_env38/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File "/web_env38/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "/web_env38/lib/python3.8/site-packages/dj_rest_auth/views.py", line 233, in post
    serializer.save()
  File "/web_env38/lib/python3.8/site-packages/dj_rest_auth/serializers.py", line 194, in save
    self.reset_form.save(**opts)
  File "/web_env38/lib/python3.8/site-packages/django/contrib/auth/forms.py", line 323, in save
    self.send_mail(
  File "/web_env38/lib/python3.8/site-packages/django/contrib/auth/forms.py", line 266, in send_mail
    body = loader.render_to_string(email_template_name, context)
  File "/web_env38/lib/python3.8/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/web_env38/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 170, in render
    return self._render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 162, in _render
    return self.nodelist.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/defaulttags.py", line 39, in render
    output = self.nodelist.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/loader_tags.py", line 53, in render
    result = self.nodelist.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/web_env38/lib/python3.8/site-packages/django/template/defaulttags.py", line 446, in render
    url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
  File "/web_env38/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File "/web_env38/lib/python3.8/site-packages/django/urls/resolvers.py", line 685, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'password_reset_confirm' not found. 'password_reset_confirm' is not a valid view function or pattern name.

I believe the problem lies in /dj_rest_auth/urls.py line 10 First name should be password_reset_confirm to refer to existing template in auth/urls.py, secondly regex must include parameters this template is called with.

# Is
path('password/reset/confirm/', PasswordResetConfirmView.as_view(), name='rest_password_reset_confirm'),
# Should be
path('password/reset/confirm/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
kos08001 commented 4 years ago
password/reset/confirm/

from - https://github.com/pennersr/django-allauth/blob/f9f09ca8346328c6bfdd3f417652e972eb1e339c/allauth/account/urls.py#L36

re_path(
    r"^password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$",
    views.password_reset_from_key,
    name="account_reset_password_from_key",
),
lukaszla commented 4 years ago

Thanks @kos08001 but I'd think this module should work correctly out of the box. And I'm not sure how the fix in another module solves my issue here if I don't want to add more dependencies.

Also I believe password/reset/confirm should not be in the email as this is an API endpoint that expects POSTand JSON data in the body. So will never work as a link from email.

What I ended up doing is customize the email completely giving my own url

kos08001 commented 4 years ago

@lukaszla The FAQ cover this - https://dj-rest-auth.readthedocs.io/en/latest/faq.html

lukaszla commented 4 years ago

Thanks, I missed it.

lifenautjoe commented 3 years ago

It would be nice to add this in the same level of importance as adding the registration urls. I had to dig through issues to realise it must be added separately.

Bergiu commented 3 years ago

I don't get it. What do i need to do to get this working? The Demo App code is not working. Why doesn't this work out of the box?

Bergiu commented 3 years ago

I have solved it by adding the file /templates/registration/password_reset_email.html with the content:

{% load i18n %}{% autoescape off %}
    {% blocktranslate %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktranslate %}

    {% translate "Please go to the following page and choose a new password:" %}
    {% block reset_link %}
        {{ protocol }}://{{ domain }}{% url 'rest_password_reset_confirm' %}
        uid: {{ uid }}
        token: {{ token }}
    {% endblock %}
    {% translate 'Your username, in case you’ve forgotten:' %} {{ user.get_username }}

    {% translate "Thanks for using our site!" %}

    {% blocktranslate %}The {{ site_name }} team{% endblocktranslate %}
{% endautoescape %}

when going live i will change reset_link to the link of the website that uses the rest-api. the predefined template isn't made to work with a rest api and makes the assumption that the website where i change my password is part of the django application, wich isn't always the case in rest-apis.