This is a fairly simple user-registration application for Django_,
designed to make allowing user signups as painless as possible.
.. _Django: http://www.djangoproject.com/
The `latest released version`_ of this application is 0.2, and is
quite stable; it's already been deployed on a number of sites. You can
also obtain the absolute freshest code from `a Subversion checkout`_,
but be warned that the code in SVN may not always be
backwards-compatible, and may well contain bugs that haven't yet been
This document covers the 0.2 release of django-registration; new
features introduced in Subversion will be added to the documentation
at the time of the next packaged release.
.. _latest released version: http://django-registration.googlecode.com/files/registration-0.2.tar.gz
.. _a Subversion checkout: http://django-registration.googlecode.com/svn/trunk/registration/
Changes from previous versions
Several new features were added between version 0.1 and version 0.2;
for details, see the CHANGELOG.txt file distributed with the packaged
One important change to note before upgrading an installation of
version 0.1 is a change to the ``RegistrationProfile`` model; the
field ``key_generated`` has been removed, since it was redundant with
the field ``date_joined`` on Django's bundled ``User`` model. Since
this field became a ``NOT NULL`` column in the database, you will need
to either drop the ``NOT NULL`` constraint or, preferably, simply drop
the column. Consult your database's documentation for the correct way
to handle this.
The only dependency for this application is a recent **SVN checkout**
of Django; this application is tracking Django's development trunk,
and has evolved to accomodate some changes which happened after the
Django 0.96 release, so a stock copy of 0.96 will not work. If you
need to use this application with Django 0.96, replace all uses of
``cleaned_data`` with ``clean_data``.
Due to use of the ``newforms`` library, this application cannot work
with Django 0.95.
This application enables a fairly common workflow for user signups:
1. User signs up for account.
2. User gets emailed an activation link.
3. User clicks the activation link before it expires.
4. User becomes a happy and productive contributor to your site.
To make this work, start by putting this app into your
``INSTALLED_APPS`` setting and running ``manage.py syncdb``. Then, add
a new setting in your settings file: ``ACCOUNT_ACTIVATION_DAYS``. This
should be a number, and will be used as the number of days before an
activation key expires.
Next, either edit the included templates (see below) to suit your
site, or create your own templates which integrate with your site's
look and feel.
Finally, drop this line into your root URLConf::
And point people at the URL ``/accounts/register/``. Things should
The download includes a set of **example** templates, which are meant
to give you an idea of how things work. However, they're taken
directly from a site which uses this application, and so they make
assumptions about that site's template structure that probably aren't
true of your site. So **it is expected that you will edit these
templates before using them**, or use them as guides to create your
own set of templates. Either way, you'll want to make sure you have a
set of templates that works with your site, and with its look and
The default template included for the activation email makes use of
the ``humanize`` template tag library, so if you use that template
"as-is" you'll need to have ``django.contrib.humanize`` in your
This app includes one model: ``RegistrationProfile``, which is tied to
the ``User`` model in ``django.contrib.auth`` via a unique foreign
key. ``RegistrationProfile`` simply stores the user's activation key.
``RegistrationProfile`` has one custom method,
``activation_key_expired``, which returns ``True`` if the key has
expired and ``False`` otherwise.
There's also a custom manager on ``RegistrationProfile`` which defines
a few useful methods:
Takes an activation key, looks up the ``RegistrationProfile``
for that key, and sets the ``is_active`` field to ``True`` on
the ``User`` associated with it. If this is successful, it
returns the ``User``. If the key was expired, or if the key
didn't correspond to any ``RegistrationProfile``, this method
Takes a username, email address and password, and first
creates a new ``User`` with those values, setting the
``is_active`` field to ``False``. Then it generates an
activation key and stores a ``RegistrationProfile`` for the
``User``. Finally, it sends an email to the user containing
the activation key. The email is generated by rendering the
template ``registration/activation_email.txt``, so edit that
template to customize the text of the email. This method
returns the new ``User`` object, in case you want to do
something with it afterwards.
To enable creation of a site-specific user profile (e.g., the
model specified in the ``AUTH_PROFILE_MODULE`` setting), pass
the optional keyword argument ``profile_callback``; the value
of this argument should be a function which, given a ``User``,
will create and save an instance of the site-specific profile
with appropriate default values.
``create_profile`` Given a ``User`` object, creates, saves and
returns a ``RegistrationProfile`` for that ``User``,
generating the activation key from a combinatino og the
``User``'s username and a random salt.
Clears out accounts which were never activated; it does this
by finding accounts which still have ``is_active`` set to
``False`` but have a ``RegistrationProfile`` with an expired
key, and deleting them. This is intended to keep your database
uncluttered and free up inactive usernames for registration,
but if for some reason you need to deactivate an account while
keeping the ``User`` in the database (say, to disable a
troublesome user's login), you can manually delete that
account's ``RegistrationProfile`` and this method will leave
Most of the time you won't need to manually write code which calls
these methods, though; the included views (see below) will take care
of them for you.
One form is included, because it's really all that's needed to handle
This form collects a username, email address and password from a
prospective user, and does a little bit of validation:
* It checks that the username is not already in use.
* It requires the user to enter the password twice (to avoid typos),
and checks that both versions match.
This is really the minimal level of validation that most people seem
to want; more advanced schemes like requiring that usernames or
passwords be at least a certain number of characters long, or also
validating the uniqueness of the email address, are best handled by
customizing the form to your own needs.
Two views are included, and between them they handle all the actual
work of registering and activating users.
This view accepts an activation key, and calls
``RegistrationProfile.objects.activate_user`` (see above) to activate
the account associated with that key.
The template used is ``registration/activate.html``, and it receives
two context variables:
The ``User`` who was activated, if activation was successful,
or ``False`` if the key was expired or didn't match any
The number of days activation keys last before they expire;
this is useful for displaying a "perhaps the account expired"
message on an unsuccessful activation.
This view signs up a new user account, by displaying and validating a
``RegistrationForm``, and calling
``RegistrationProfile.objects.create_inactive_user`` (see above) once
it gets valid data.
The template used is ``registration/registration_form.html``, and it
receives a context variable named ``form``, which is the
``RegistrationForm`` instance. It also uses ``RequestContext``, so any
context processors you've enabled on your site will be applied as
On successful registration, this view issues a redirect; the default
URL of the redirect is ``/accounts/register/complete/``, but you can
override this by passing the keyword argument ``success_url`` into the
To enable creation of a site-specific user profile, pass the optional
keyword argument ``profile_callback`` to this view; see the
``create_inactive_user`` method of the manager on
``RegistrationProfile`` (documented above) for details.
The default URLConf included with this application maps the following
URL fragments to the following views:
Maps to ``registration.views.activate``. Note that this URL
will match any string as ``activation_key``; the pattern will
be checked to see if it matches the format of a SHA1 hash
before any database lookup happens, but allowing anything to
match here means you can show a useful "this key is invalid"
message instead of a confusing 404 when the format isn't
Maps to ``registration.views.register``.
Maps to ``django.views.generic.simple.direct_to_template``,
using the template
Maps to ``django.contrib.auth.views.login``.
Maps to ``django.contrib.auth.views.logout``.
A good place to include this URLConf if you use it directly is at
There are two problems you're likely to run into: one is not editing
the default template set (see above for why you need to do that), and
will lead either to errors about a base template not existing, or to a
mismatch between names of blocks in your site's base template and
names of blocks in the default template set.
The other problem you're likely to see is users complaining that they
didn't get their activation emails. This is most likely due to
overzealous spam filtering by their ISP or email provider;
unfortunately, many spam filters eat account registration emails for
breakfast. If you can solve that problem, you will make millions of
What this application does not do
This application also does not integrate in any way with OpenID, nor
should it; one of the key selling points of OpenID is that users
**don't** have to walk through an explicit registration step on every
site they want to use :)
If you spot a bug
Head over to this application's `project page on Google Code`_ and
check `the issues list`_ to see if it's already been reported. If not,
open a new issue and I'll do my best to respond quickly.
.. _project page on Google Code: http://code.google.com/p/django-registration/
.. _the issues list: http://code.google.com/p/django-registration/issues/list