Setting up Django Registration

Django’s admin framework includes the basic functionalities for logging in and out of the admin site, but if you’re building a so-called ‘social’ application and want people to be able to sign-up, log in and thus benefit from additional site functionalities then you need to use a more generic ‘registration’ application. The good news is: most of the work has already been done, so it’s just a matter of putting things together correctly.

I found a nicely written blog post on this topic, so in what follows I’m just doing a re-cap of the main steps involved and adding some other useful info.

Before we start: what follows has been tested on Django 1.1 Django 1.3, Python 2.6 and MySQL (note: on 13/8/12 I revised this post so that the code would work on django 1.3 – many thanks to the folks who left comments and pointed out what needed to be updated!)

1) Install

Download the package from bitbucket and add it to your application directory (or put it somewhere else and then modify your python path as needed). Then add the ‘registration’ app to the installed_apps tuple in your settings.py:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.humanize',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    # etc..
    'registration',
)

2) Syncdb

Do a quick syncdb from the console, which will result in one new table being created in the DB, ‘RegistrationProfile’. All it contains is its primary key, the ‘user’ key, and the ‘activation code’ fields. Now we’ve got the data structures needed for setting up the registration application!

> python manage.py syncdb

3) Setting.py

Create some registration settings in settings.py:

ACCOUNT_ACTIVATION_DAYS=7
EMAIL_HOST='localhost'
EMAIL_PORT=1023
EMAIL_HOST_USER='username'
EMAIL_HOST_PASSWORD='password'

Obviously you’ve got to change the settings above depending on your specific server setup (more information is available here or here). Also, see point 7 below if you’re just testing things out without a SMTP server available.

4) Urls.py

Include the required registration urls to your urls.py:

urlpatterns = patterns(",
  (r'^admin/', include('django.contrib.admin.urls')),
  (r'^accounts/', include('registration.urls')),
)

5) Templates

Add the registration templates to your django-templates directory. The django-registration package we downloaded earlier on doesn’t include any templates, but you can easily find some of them online (for example here).
Anyways, no need to do that: I took those templates and added some other ones too so to create the minimal working package that’ll get you going (that doesn’t include any fancy css styling but all the basic html stuff is there). You can download the templates here, expand the zip file and put it in templates/registration.

6) Done! Let’s recap..

We’re now ready to go. Let’s pause for a moment and recap what we achieved: we installed and activated django-registration, which sets up a whole bunch of new urls. These are divided into two groups:

a) /login, /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/.
This is the original URL specification source code (you can see it on bitbucket too) :

# from django-registration / registration / auth_urls.py
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,
                            {'template_name': 'registration/password_change_form.html'},
                           name='auth_password_change'),
                       url(r'^password/change/done/$',
                           auth_views.password_change_done,
                            {'template_name': 'registration/password_change_done.html'},
                           name='auth_password_change_done'),
                       url(r'^password/reset/$',
                           auth_views.password_reset,
                            {'template_name': 'registration/password_reset_form.html'},
                           name='auth_password_reset'),
                       url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
                           auth_views.password_reset_confirm,
                            {'template_name': 'registration/password_reset_confirm.html'},
                           name='auth_password_reset_confirm'),
                       url(r'^password/reset/complete/$',
                           auth_views.password_reset_complete,
                            {'template_name': 'registration/password_reset_complete.html'},
                           name='auth_password_reset_complete'),
                       url(r'^password/reset/done/$',
                           auth_views.password_reset_done,
                            {'template_name': 'registration/password_reset_done.html'},
                           name='auth_password_reset_done'),
)

b) the second group of urls are /activate and /register:
This is the original URL specification source (see it on bitbucket) :

# django-registration / registration / backends / default / urls.py 
urlpatterns = patterns('',
                       url(r'^activate/complete/$',
                           direct_to_template,
                           { 'template': '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+)/$',
                           activate,
                           { 'backend': 'registration.backends.default.DefaultBackend' },
                           name='registration_activate'),
                       url(r'^register/$',
                           register,
                           { 'backend': 'registration.backends.default.DefaultBackend' },
                           name='registration_register'),
                       url(r'^register/complete/$',
                           direct_to_template,
                           { 'template': 'registration/registration_complete.html' },
                           name='registration_complete'),
                       url(r'^register/closed/$',  # UNUSED
                           direct_to_template,
                           { 'template': 'registration/registration_closed.html' },
                           name='registration_disallowed'),
                        # this is the default django login module 
                       (r'', include('registration.auth_urls')),
                       )

7) Testing

If you’re testing things on a development server you might not have access to an SMTP server (needed to test the email-based registration process). In such a case you can still try out your application using a workaround. In your settings.py file change the registration settings with the following ones:

EMAIL_HOST = 'localhost'
EMAIL_PORT = 1025
EMAIL_HOST_USER = "
EMAIL_HOST_PASSWORD = "
EMAIL_USE_TLS = False
DEFAULT_FROM_EMAIL = 'testing@example.com'

Then open up another console window and run a temporary ‘dummy’ SMTP server with python:

bash-3.2$ python -m smtpd -n -c DebuggingServer localhost:1025

This local SMTP server remains there waiting for incoming messages. If now you go to /accounts/register/, fill out the form and hit ‘send’ you’ll see the registration email printed out in the console. Basically what happened is this: the ‘dummy’ python SMTP server we’ve just set up picked up django’s email-sending request and consequently printed out the email contents. If this is indeed what happened, it means that your code is working properly… and that you can use the url provided in the email to test the activation functionality too.

For example, here is what you would see in the console after registering:


---------- MESSAGE FOLLOWS ----------
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Subject: Activate your djangoproject.com account - you have 2 days!
From: testing@example.com
To: michele.pasin@hotmail.com
Date: Wed, 12 Jan 2011 16:49:59 -0000
Message-ID: <20110112164959.3366.35638@mymac.local>
X-Peer: 127.0.0.1


Someone, hopefully you, signed up for a new account at djangoproject.com using this email address. If it was you, and you'd like to activate and use your
account, click the link below or copy and paste it into your web browser's address bar:

http://127.0.0.1:8000/accounts/activate/6342fca5ffd430a820be6d98acde6e59a4c2d29c/

If you didn't request this, you don't need to do anything; you won't receive any more email from us, and the account will expire automatically in two days.

------------ END MESSAGE ------------

Pasting the ‘activation’ url in your browser should allow you to complete the registration process and check the rest of your code.

Finally, keep in mind also that the django-registration application sends out emails that contain your site’s URL for the activation link, and that URL is dynamically determined using the ‘sites’ application (normally added via settings.py). By default, your domain name is listed as ‘example.com’, and the easiest way to change this is to log into the admin application and click on the ‘Sites’ link on the admin home page to get to the relevant entry.

===== ++ =====

Some other possibly useful links:

Fromt the Django website:

  • User authentication in django
  • Sending emails
  • From the Django book:

  • Chapter 12: Sessions, users, and registration
  •  

    Share/Bookmark






    23 Responses to “Setting up Django Registration”

    Cool, nice post. As Django newbie, I followed it step by step and the setup went smooth. Cheers! :)

    56k added these pithy words on Feb 04 11 at 2:30 pm

    Unfortunately I get this.

    Reason given for failure:
    CSRF token missing or incorrect.

    In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django’s CSRF mechanism has not been used correctly. For POST forms, you need to ensure:

    maraka added these pithy words on Oct 13 11 at 3:06 am

    @maraka: That has to do with the extra security layer added to recent django versions; there might be a variety of causes why you get the error, this page could help you though: http://stackoverflow.com/questions/1765723/django-csrf-framework-having-many-failures

    mike added these pithy words on Oct 13 11 at 8:22 am

    I’m getting the exact same CSRF error as maraka… too bad, I was so stoked to have it almost working! This was really the best tutorial I found on this topic. <3

    Mia added these pithy words on Nov 09 11 at 12:49 am

    Fixed issue by adding {% csrf_token %} after the opening of the form

    Mia added these pithy words on Nov 09 11 at 1:21 am

    […] into it earlier but the tutorials were all confusing to me. I finally found one that made sense by Michele Pasin, in which setting up the registration package, the views and the SMTP debugging server are […]

    Django Registration, Authentication and User’s Names | Simple App Group, LLC added these pithy words on Feb 26 12 at 9:03 pm

    Very nice tutorial. It works for me, a django newbie, using django 1.4 after I added the {% csrf_token %} to forms as
    someone suggested.
    (A minor point: some of your code snippets contain
    “smart” quotes. Straight quotes would make copying and pasting
    easier.)

    pskin added these pithy words on May 22 12 at 12:31 am

    Great tutorial.

    Like others, I had to:
    – add the {% csrf_token %} in the template registration_form.html below the opening tag
    – add the app ‘django.contrib.humanize’ to the list of INSTALLED_APPS in settings.py
    – convert the “strange” quotes that you use in your code snippets and change them into regular quotes to avoid encoding errors

    Ziegen added these pithy words on Jun 06 12 at 1:43 am

    Thanks! I updated the post (fixed the smart quotes issue) and the templates (added the csrf token tag) so now it all should be working on django 1.3..

    mike added these pithy words on Aug 13 12 at 5:29 pm

    I tried all the steps but I am getting this error
    “Import error at /login/
    no module named urls”
    I am adding django registration to my web app
    and in the settings.py when I change
    ROOT_URLCONF=’myapp.urls’to
    ROOT_URLCONF=’registration.urls’ then it works fine
    but then I cannot get my site views to work
    please help I am just starting to learn django

    saad added these pithy words on Sep 11 12 at 2:04 pm

    Hi saad,
    your ROOT_URLCONF variable normally should point at the main urls.py file for your django project, not the registration app. In order to link up the registration app you should just modify the main urls.py file as described in point 4 above.

    mike added these pithy words on Sep 11 12 at 2:33 pm

    The simple template using humanize
    {% load humanize %}
    so..
    need ‘django.contrib.humanize’ on INSTALLED_APPS.

    hope you are mind to edit the post, and yeah, it’s very useful and detailed.

    Thanks and sorry

    Shy added these pithy words on Oct 07 12 at 5:19 pm

    oh ya,
    and for “mike on Sep 11 12 at 2:33 pm”
    and anyone else having the “url” problem.

    I commented a line to
    # (r’^admin/’, include(‘django.contrib.admin.urls’)),
    on urls.py

    it works for me, and hope it will work too for some random people.

    Sorry and Thanks :)

    Shy added these pithy words on Oct 07 12 at 5:24 pm

    This is a really great tutorial; thanks for putting it together! I’ve followed it and got everything working. I have one question:

    Is there a way to set it up so that once the user clicks the confirmation link and goes to the website, the user is logged in as a result? Right now, it seems that the confirmation activates the user, but then the user still has to click login and fill in his login details.

    Thanks

    Frank V added these pithy words on Jan 16 13 at 3:10 pm

    In your activate.html ,there is a line {% if account %} .Where does the account object come from?

    Sajanjoseph added these pithy words on Jan 30 13 at 1:47 pm

    Great tutorial. Up and running in no time, Thanks.

    Designer023 added these pithy words on Jun 21 13 at 3:20 pm

    The current URL, accounts/, didn’t match any of these.

    ^accounts/

    ^activate/complete/$
    [name=’registration_activation_complete’]

    and so on.
    any solution?
    i am just a noob :(

    Mrinmoy Das added these pithy words on Jul 03 13 at 6:33 am

    Brilliant tutorial, Got it working like a charm. Awesome thanks.

    rakesh manohar added these pithy words on Nov 03 13 at 7:24 pm

    Thanks for the post it will help me roll out my new site soon

    Ham Kibz added these pithy words on Nov 17 13 at 2:12 pm

    Be careful when cutting-and-pasting the code here. The email config in section 7 uses one / double quote in two places where there should be two / single quotes. Python syntax error.

    face_facts added these pithy words on Apr 25 14 at 7:06 am

    I thought I should point out that the login.html template included in this tutorial includes the line :

    {% csrf_token %}

    this means the default behaviour is to redirect to / following successful login, not to the url specified by LOGIN_REDIRECT_URL in urls.py, which stumped me for a while . To redirect to LOGIN_REDIRECT_URL, just remove |default:”/” :

    {% csrf_token %}

    Hopefully I’ll have saved someone from a bit of head scratching.

    Dylan Ross added these pithy words on Aug 03 14 at 10:19 am

    thanks Dylan that’s a very good point

    Mikele added these pithy words on Aug 04 14 at 11:23 am

    Hi, does anyone have a clue on how to implement two step authentication with this module ?

    Flavio added these pithy words on Jun 06 16 at 4:54 pm