Search code examples
djangopython-2.7django-authenticationdjango-registration

Namespacing urls in django-registration


I want to keep a clean urls description in my projet, so I use namespaces:

project/urls.py:

urlpatterns = patterns('',
url(r'^contracts/', include('apps.contracts.urls', namespace='contracts')),
url(r'^accounts/', include('apps.registration_custom.backends.vince.urls', namespace='accounts')),

registration_custom/backends/vince/urls.py:

urlpatterns = patterns('',
                   url(r'^activate/complete/$',
                       TemplateView.as_view(template_name='registration/activation_complete.html'),
                       name='registration_activation_complete'),
                   # Activation keys get matched by \w+ instead of the more specific
                   # [a-fA-F0-9]{40} because a bad activation key should still get to the view;
                   # that way it can return a sensible "invalid key" message instead of a
                   # confusing 404.
                   url(r'^activate/(?P<activation_key>\w+)/$',
                       ActivationView.as_view(),
                       name='registration_activate'),
                   url(r'^register/$',
                       CustomRegistrationView.as_view(),
                       name='registration_register'),
                   url(r'^register/complete/$',
                       TemplateView.as_view(template_name='registration/registration_complete.html'),
                       name='registration_complete'),
                   url(r'^register/closed/$',
                       TemplateView.as_view(template_name='registration/registration_closed.html'),
                       name='registration_disallowed'),
                   (r'', include('registration.auth_urls')),
                   )

With this configuration, if I request /accounts/password/reset/ I get an error:

Reverse for 'django.contrib.auth.views.password_reset_done' with arguments '()' and keyword arguments '{}' not found

But if I'm not namespacing my urls, everything goes clean with my /accounts/password/reset/ request.

What I understand is that the django/contrib/auth/views/password_reset view is using reverse() on 'django.contrib.auth.views.password_reset_done'. And the urls dispatcher get lost because it should be asking for 'accounts:auth_password_reset_done'.

Am I guessing right?

Then what would be my options?

EDIT. The template code that redirect to /accounts/password/reset :

{% extends "base.html" %}
{% load i18n %}

{% block content %}
<form method="post" action="">
  {% csrf_token %} 
  {{ form.as_p }}

  <input type="submit" value="{% trans 'Log in' %}" />
  <input type="hidden" name="next" value="{{ next }}" />
</form>

<p>{% trans "Forgot password" %}? <a href="{% url 'accounts:auth_password_reset' %}">{% trans "Reset it" %}</a>!</p>
<p>{% trans "Not member" %}? <a href="{% url 'accounts:registration_register' %}">{% trans "Register" %}</a>!</p>
{% endblock %}

Solution

  • Wahaha, I've made a step in my Django's comprehension!

    In fact, Django auth module is looking for a view when he asks for: reverse('django.contrib.auth.views.password_reset_done')

    But my urls config is namespaces, so Django is lost (here I don't know exactly, maybe someone can explain better).

    So I need to say to Django to look first for a non-namespaced url pattern first, just for it's core code.

    So my trick is to add a line in the myproject/urls.py:

    urlpatterns = patterns('',
    url(r'^contracts/', include('apps.contracts.urls', namespace='contracts')),
    
    # this is tricky
    # the default auth module need to reverse some urls like reverse('django.contrib.auth.views.password_reset_done')
    # but I want to keep a namespaced urls config
    # then I need to supply a first url path to django when he look at non-namespaced urls
    url(r'^accounts/', include('registration.auth_urls')),
    url(r'^accounts/', include('apps.registration_custom.backends.vince.urls', namespace='accounts')),
    

    And everything is working fine!

    I admit that this is not an elegant solution, but it has the benefit to keep my namespaces right, so will be the templates.