Custom user models

When django-registration was first developed, Django’s authentication system supported only its own built-in user model, django.contrib.auth.models.User. More recent versions of Django have introduced support for custom user models.

Older versions of django-registration did not generally support custom user models due to the additional complexity required. However, django-registration now can support custom user models. Depending on how significantly your custom user model differs from Django’s default, you may need to change only a few lines of code; custom user models significantly different from the default model may require more work to support.

Overview

The primary issue when using django-registration with a custom user model will be RegistrationForm. RegistrationForm is a subclass of Django’s built-in UserCreationForm. The only changes made by django-registration are:

Django’s UserCreationForm is a ModelForm with its model hard-coded to django.contrib.auth.models.User. As a result, you will always be required to supply a custom form class when using django-registration with a custom user model, if only to specify the correct model.

In the case where your user model is compatible with the default behavior of django-registration, (see below) you will be able to subclass RegistrationForm, set it to use your custom user model as the model, and then configure the views in django-registration to use your form subclass. For example, you might do the following (in a forms.py module somewhere in your codebase – do not directly edit django-registration’s code):

from django_registration.forms import RegistrationForm

from mycustomuserapp.models import MyCustomUser


class MyCustomUserForm(RegistrationForm):
    class Meta(RegistrationForm.Meta):
        model = MyCustomUser

You will also need to specify the fields to include in the form, via the fields declaration.

And then in your URL configuration (example here uses the two-step activation workflow):

from django.conf.urls import include, url

from django_registration.backends.activation.views import RegistrationView

from mycustomuserapp.forms import MyCustomUserForm


urlpatterns = [
    # ... other URL patterns here
    url(r'^accounts/register/$',
        RegistrationView.as_view(
            form_class=MyCustomUserForm
        ),
        name='django_registration_register',
    ),
    url(r'^accounts/',
        include('django_registration.backends.activation.urls')
    ),
    # ... more URL patterns
]

If your custom user model is not compatible with the built-in workflows of django-registration (see next section), you will probably need to subclass the provided views (either the base registration views, or the views of the workflow you want to use) and make the appropriate changes for your user model.

Determining compatibility of a custom user model

The built-in workflows and other code of django-registration do as much as is possible to ensure compatibility with custom user models: Django provides numerous facilities for retrieving and introspecting the user model without hard-coding a particular model class or field names, and django-registration makes use of them.

However, there are still some specific requirements you’ll want to be aware of.

The two-step activation workflow

The two-step activation requires that the following be true of your user model:

  • It must set the attribute USERNAME_FIELD to denote the field used as the username, and must define the method get_username() for retrieving the username value. Subclasses of Django’s AbstractBaseUser receive this attribute and method automatically.
  • It must have a field for storing an email address, and it must define the method get_email_field_name(), which will return the name of the email field. Subclasses of Django’s AbstractBaseUser receive this method automatically (and the backing attribute EmailField which normally stores the name of the email field). This field must be a textual field type (EmailField, CharField or TextField). Note that this field will be required by RegistrationForm, which is a difference from Django’s default UserCreationForm.
  • The username and email fields must be distinct. If you wish to use the email address as the username field, you will need to supply your own completely custom registration form.
  • It must have a field named is_active, and it must be a BooleanField indicating whether the user’s account is active.

If your custom user model defines additional fields beyond the minimum requirements, you’ll either need to ensure that all of those fields are optional (i.e., can be NULL in your database, or provide a suitable default value defined in the model), or you’ll need to specify the full list of fields to display in the fields section of the Meta declaration of your RegistrationForm subclass.

The one-step workflow

The one-step workflow places the following requirements on your user model:

  • It must set the attribute USERNAME_FIELD to denote the field used as the username, and must define the method get_username() for retrieving the username value. Subclasses of Django’s AbstractBaseUser receive this attribute and method automatically.
  • It must define a field named password for storing the user’s password (it will expect to find the value in the field password1 of the registration form).

Also note that RegistrationForm requires the email field, so either provide that field on your model or subclass RegistrationForm and override to remove the email field or make it optional.

If your custom user model defines additional fields beyond the minimum requirements, you’ll either need to ensure that all of those fields are optional (i.e., can be NULL in your database, or provide a suitable default value defined in the model), or you’ll need to specify the full list of fields to display in the fields section of the Meta declaration of your RegistrationForm subclass.

Because the one-step workflow logs in the new account immediately after creating it, you must either use Django’s ModelBackend as an authentication backend, or use an authentication backend which accepts a combination of USERNAME_FIELD and password as sufficient credentials.