Development Doodles

User authentication with django-registration

February 16, 2009 · 21 Comments

The built-in user authentication system in Django is great, but unfortunately it lacks support for sending activation emails to newly registered users. Enter the django-registration application, which adds registration and account activation on top of Django’s standard views for user authentication.

Although certainly not the first of its kind, this post will cover the steps I took to get it up and running for a freshly created Django project. Other tutorials are available here, here and here, as well as in the official documentation.

Step 1 — install django-registration
Instructions on how to install django-registration are covered nicely by the official overview document. You can also simply copy the registration folder directly to your project folder, which enables you to modify the contents of the package specifically for your project, should you wish to do so.

Step 2 — update settings.py
Add the registration application to the INSTALLED_APPS tuple in settings.py. Also add django.contrib.admin if you want to make use of Django’s admin system to handle user accounts (of course you do!). It might look like this:

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

I also added the following settings:

ACCOUNT_ACTIVATION_DAYS = 2
EMAIL_HOST = 'localhost'
DEFAULT_FROM_EMAIL = 'webmaster@localhost'
LOGIN_REDIRECT_URL = '/'

Strictly speaking, only the first setting is required. It controls how many days emailed activation keys are valid.

EMAIL_HOST should be set to whatever host name your mail server is on. It defaults to ‘localhost’, but it’s explicitly set in the above example for clarity. You should also change the DEFAULT_FROM_EMAIL setting to show a proper sender email address for your activation emails.

Finally, LOGIN_REDIRECT_URL controls where a user is redirected after successful login by the contrib.auth.login view. The default value /accounts/profile/ is fine if you intend to map a view to that URL, but django-registration doesn’t do this for us so we’ll just use ‘/’ for now.

Step 3 — setup database
In addition to the standard Django user models, django-registration needs an additional model (RegistrationProfile) for storing activation keys that are sent out. Set this model up in the database by running:

python manage.py syncdb

Step 4 — update urls.py
The root urls.py needs to be updated with mappings for the registration application and admin. django-registration maintains its own mappings inside ./registration/urls.py, so we just delegate to that file:

from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),
    (r'^accounts/', include('registration.urls')),
    (r'^$', direct_to_template,
            { 'template': 'index.html' }, 'index'),
)

This example also adds a mapping for the ‘/’ URL we added a redirect to in step 2, which directly forwards to an index.html template.

Step 5 — create view templates
All that remains now is to create rendering templates for the registration views. They should go into a ‘registration’ folder under your template root (TEMPLATE_DIRS in settings.py).

django-registration maps URLs to the standard django.contrib.auth.views, so the following templates need to be created:

login.html — user login form
logout.html — shown after a user has logged out
password_change_form.html — password change form
password_change_done.html — shown after successful password change
password_reset_form.html — ask user for email to send password-reset mail to
password_reset_email.html — template for password-reset mail
password_reset_done.html — shown after password-reset email has been sent
password_reset_confirm.html — ask user for new password after reset
password_reset_complete.html — shown after successful password reset

Note that the password_reset_confirm and password_reset_complete views are missing from the official documentation, but it’s possible to see how they can be used in the Django source code here, here, and here.

Additionally, the following templates specific to django-registration need to be created:

registration_form.html — user registration form
registration_complete.html — shown after a user has registered
activation_email_subject.txt — subject of activation email
activation_email.txt — template for activation email
activate.html — shown after a user has activated his account

I’ve created very basic example implementations of these templates that you can download here.

Step 6 — change site name and domain
The email templates will normally output both the domain name and display name for your web site. To change the default value of “example.com” to the name of your web site you need to log in to the admin system and go to the Sites section (/admin/sites/site/), where you can edit this.

Step 7 — done
That should be all, I hope. ;-)

Categories: Development
Tagged: , ,

21 responses so far ↓

  • Michael T. // March 11, 2009 at 18:48

    Thanks for a great tutorial!

  • devdoodles // March 11, 2009 at 20:08

    Thanks, I’m glad you found it useful!

  • Bastien // March 13, 2009 at 16:05

    If you know any place where I can find information about how to extend the functions you would brighten my day.

    I’m trying to have different classes of users: simple users can register themselves and automatically go in the simple group and on the other side special users need an admin approval and go to the special group.

    I’m swiming in the code and django doc right now but any light would be appreciated. Thanks for this article.

  • devdoodles // March 13, 2009 at 20:44

    Although it’s not quite clear to me what you want to do, it sounds as if you might want to read up on user permissions and groups in the Django auth documentation. By checking which permissions a user have, or which groups he/she belongs to, you can adapt how the site works for your two user groups:

    http://docs.djangoproject.com/en/dev/topics/auth/

    As for the actual registration step, I’m not sure how you want to handle the “special” users or what criterion marks a user as special. If both groups are meant to be able to register on their own and by default go into the “simple” group, then I think you don’t need to change the django-registration code at all. The admin approval step could just be someone updating the permissions/groups for the user in the admin interface.

    However, if the special-group users should not become active at all before admin approval has been made, you would have to change the register() and activate() views (and dependent logic) in django-registration to accommodate this.

  • aleksandar // June 9, 2009 at 21:16

    Link with templates is dead. Can you please reupload.

  • devdoodles // June 10, 2009 at 00:20

    Sorry about that, my server got taken down as a result of the vaserv.com wipe this week. The link should be working again within an hour.

  • Michael h, DK // August 1, 2009 at 00:53

    Hi and thanks for posting this fine article howto.

    I have a little problem though. Cant login. I keep getting thrown out. I get fine error msg’es when I use wrong username or passw. But when I use the correct username and passw, then I just get thrown back to the login.
    Any idea what I did wrong?
    Thanks again :o )

  • Michael h, DK // August 1, 2009 at 01:08

    Hi again. It must be something mysterious, cause it seems to work in another browser. I played alot with the reset password stuff and that might have messed up something in session. I dont know… But I think its solved. Thanks anyway :o )

  • Ben // August 25, 2009 at 03:36

    Thanks for the example templates – very much appreciated.

  • dbaer // August 27, 2009 at 20:37

    Thank you very much! Helped me a lot.
    I did the following to have the link sent through my gmail-account:
    EMAIL_USE_TLS = True
    EMAIL_HOST = ’smtp.gmail.com’
    EMAIL_HOST_USER = ‘@gmail.com’
    EMAIL_HOST_PASSWORD = ”
    EMAIL_PORT = 587

  • Volkan Oransoy // August 29, 2009 at 16:18

    Thank you, this tutorial helped me a lot. Especially zipped templates file.

  • devdoodles // August 29, 2009 at 17:00

    Thanks guys, I appreciate the feedback!

  • Thomas // September 7, 2009 at 05:01

    Hello, I am with some trouble… I will appreciate any help…
    I follow the tutorial and made double check but I still getting some problem.
    When I access “login” I get this error:
    DoesNotExist at /accounts/login/

    if I access /accounts/register/ the template will open without problem, but after submit another error happen…

    Could someone help me?

    You can see this errors accessing http://www.spire.com.br

    Thanks

  • Thomas // September 7, 2009 at 22:31

    Well… The problemas was solved… I just droped all databases and re-create… But I have no idea why it works now…

  • devdoodles // September 7, 2009 at 23:14

    Good that you found a solution, even if it was no explanation. :-) Did you get any other message than DoesNotExist?

    The only suggestion I found from a quick search was that some people got this problem when django.contrib.sites wasn’t loaded or when there was no site model matching the site ID. If this was the problem in your case I don’t know…

  • Thomas // September 7, 2009 at 23:51

    Yes devdodles, I think the problem is around there :-)
    I deleted the “example.com” and created one with my domain. Maybe there is the trouble, I should just rename and not delete/create. But I am not really sure if it was the problem.

    Thanks anyway! Everything is working now.

  • Thomas // September 8, 2009 at 00:44

    Maybe a silly question. :-p

    After login I am loosing auth session for some pages. If I access “accounts/login/”,”accounts/logout/”,”"accounts/register/” the session always will be there, but if I access different page I cant access the user variable.

    This is strange because I am using the same “base.html” for all pages and inside has the logic “if user.is_authenticated”, how I said this condition is true just when I access pages that have “accounts” in the URL.

    in the settings file I enabled theses three middleware:

    MIDDLEWARE_CLASSES = ( ‘django.middleware.common.CommonMiddleware’, ‘django.contrib.sessions.middleware.SessionMiddleware’, ‘django.contrib.auth.middleware.AuthenticationMiddleware’, )

    Thanks

  • devdoodles // September 8, 2009 at 08:02

    I’m guessing you’re not passing a RequestContext() to the templates that aren’t working. The user object is only available in RequestContexts, not the base Context that is passed by default. If you’re using render_to_response() you can pass a RequestContext by adding context_instance=RequestContext(request) as a parameter to the call.

  • Thomas // September 9, 2009 at 00:28

    Yes, you are right.

    I just needed import “from django.template import RequestContext”
    and add this parameter.

    Thanks a lot.

  • Django IA: Registration-Activation « streamhacker.com // September 29, 2009 at 22:54

    [...] basic idea is that an anonymous user can create a new account, but cannot login until they activate their account by clicking a link they’ll receive in an activation email. It’s a way to automatically [...]

  • reese // October 28, 2009 at 15:32

    Hi! Nice explanation.
    Just one question: how do you setup a link in order to activate users?

    Something like
    accounts/activation/?key=oijr32orj23rj32orj34o

    And then call the activate_user(key) in a view?

Leave a Comment