+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 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
+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
+Next, either edit the included templates (see below) to suit your
+site, or create your own templates which integrate with your site's
+Finally, drop this line into your root URLConf::
+ (r'^accounts/', include('registration.urls')),
+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
+and the date/time when the key was generated.
+``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
+ 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.
+ 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
+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
+ 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
+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
+The default URLConf included with this application maps the following
+URL fragments to the following views:
+ ``activate/<activation key>/``
+ 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``,
+ 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 does not take custom user profiles (as specified in
+the ``AUTH_PROFILE_MODULE`` setting) into account, and will neither
+look for them nor try to create instances of them for you. If you're
+using a custom profile model, you'll want to either write your own
+registration view which can create an instance of it on
+registration/activation, or else use Django's dispatcher to hook into
+the ``post_save`` signal of ``User`` or ``RegistrationProfile`` and
+automatically create an instance of your profile model.
+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 :)
+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