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






    • 56k

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

    • maraka

      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:

    • Mia

      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

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

    • Pingback: Django Registration, Authentication and User’s Names | Simple App Group, LLC()

    • pskin

      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.)

    • Ziegen

      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

      • mike

        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..

    • saad

      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

      • mike

        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.

    • Shy

      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

      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 :)

    • Frank V

      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

    • Sajanjoseph

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

    • Designer023

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

    • Mrinmoy Das

      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 :(

    • rakesh manohar

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

    • Ham Kibz

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

    • face_facts

      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.

    • Dylan Ross

      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.

      • thanks Dylan that’s a very good point

    • Flavio

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