Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-nonrel + Django-registration problem: unexpected keyword argument 'uidb36' when resetting password

I'm using Django-nonrel with registration app. Things seem to be working fine, except when I try to reset my password. When clicking on reset-password link sent to me in email, Django produces error message:

password_reset_confirm() got an unexpected keyword argument 'uidb36'

My question: has anybody seen it and knows what's the cure?

EDIT:

The problem is caused by registration\auth_urls.py - they duplicate entries in django\contrib\auth\urls.py, circumwenting patched version of the file in Django-nonrel.

Any ideas why is it there and can I actually remove it or fix it otherwise?

like image 867
mhl666 Avatar asked Jun 12 '11 18:06

mhl666


4 Answers

Django 1.6 uses base 64 encoding for the User's ID instead of base 36 encoding.

If you have any custom password reset URLs, you will need to update them by replacing uidb36 with uidb64 and the dash that follows that pattern with a slash. Also add "_", "\" and "-" to the list of characters that may match the uidb64 pattern.

For example this line in urls.py in Django 1.5-:

url(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
    'django.contrib.auth.views.password_reset_confirm',
    name='password_reset_confirm'),

Will need to be changed to this in Django 1.6+:

url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
    'django.contrib.auth.views.password_reset_confirm',
    name='password_reset_confirm'),

Here is the official changelog which details the change: https://docs.djangoproject.com/en/1.6/releases/1.6/#django-contrib-auth-password-reset-uses-base-64-encoding-of-user-pk

like image 146
Aidan Avatar answered Nov 06 '22 16:11

Aidan


My solution was to comment out urlpatterns defined in registration\auth_urls.py, and redefine them as a copy of urlpatterns defined in django.contrib.auth.

Here's my auth_urls.py after the change:

"""
URL patterns for the views included in ``django.contrib.auth``.

Including these URLs (via the ``include()`` directive) will set up the
following patterns based at whatever URL prefix they are included
under:

* User login at ``login/``.

* User logout at ``logout/``.

* The two-step password change at ``password/change/`` and
  ``password/change/done/``.

* The four-step password reset at ``password/reset/``,
  ``password/reset/confirm/``, ``password/reset/complete/`` and
  ``password/reset/done/``.

The default registration backend already has an ``include()`` for
these URLs, so under the default setup it is not necessary to manually
include these views. Other backends may or may not include them;
consult a specific backend's documentation for details.

"""

from django.conf.urls.defaults import *

#from django.contrib.auth import views as auth_views

from django.contrib.auth import urls as auth_urls

urlpatterns = auth_urls.urlpatterns

'''
Commented out, this is what caused my problems:

urlpatterns = patterns('',
                       url(r'^login/$',
                           auth_views.login,
                           {'template_name': 'registration/login.html'},
                           name='auth_login'),
                       url(r'^logout/$',
                           auth_views.logout,
                           {'template_name': 'registration/logout.html'},
                           name='auth_logout'),
                       url(r'^password/change/$',
                           auth_views.password_change,
                           name='auth_password_change'),
                       url(r'^password/change/done/$',
                           auth_views.password_change_done,
                           name='auth_password_change_done'),
                       url(r'^password/reset/$',
                           auth_views.password_reset,
                           name='auth_password_reset'),
                       url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
                           auth_views.password_reset_confirm,
                           name='auth_password_reset_confirm'),
                       url(r'^password/reset/complete/$',
                           auth_views.password_reset_complete,
                           name='auth_password_reset_complete'),
                       url(r'^password/reset/done/$',
                           auth_views.password_reset_done,
                           name='auth_password_reset_done'),
) 
'''
like image 26
mhl666 Avatar answered Nov 06 '22 15:11

mhl666


I just had to change the uidb36 argument to uidb64, like so:

FROM:

url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',

TO:

url(r'^password/reset/confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',

Then password resets began working again.

like image 5
Matt Williamson Avatar answered Nov 06 '22 14:11

Matt Williamson


I guess your password_reset_confirm url in urls.py looks something similar to

url(r'^accounts/password_reset/(?P[0-9A-Za-z]{1,13})-(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', password_reset_confirm, {'post_reset_redirect' : '/accounts/password_reset/complete/'},name="password_reset_confirm"),

and your link in password_reset_email.html looks like {{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb36=uid token=token %}

Just change uib36 to uib64 both the places,it works.

like image 1
MANOJ REDDY Avatar answered Nov 06 '22 14:11

MANOJ REDDY