Using custom user models

This app was created to be used with custom user models, which were introduced in Django 1.5. While the basic configuration in Setup allows you to use django-signup with the default user model, some extra configuration is needed in order to work with custom user models.

The custom user model

Consider the following user model and associated manager:

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models

class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None):
        if not email:
            raise ValueError('missing email')
        user = self.model(email=email)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        #for this example, nothing special happens here
        return self.create_user(email, password)

class CustomUser(AbstractBaseUser):
    email = models.EmailField(
        max_length=254,
        unique=True,
        db_index=True
    )

    objects = CustomUserManager()

    USERNAME_FIELD = 'email'

    def get_short_name(self):
        return self.email
    def get_full_name(self):
        return self.email

This model has, in practice, two fields: email and password, the latter which is provided by AbstractBaseUser.

The custom sign up form

Requirements

When this user model is installed (see the docs), it is already available to Django, but django-signup requires you to create a custom version of what Django provides as UserCreationForm.

This form should have all the necessary information needed to create a custom user model instance through the CustomUser.objects.create_user method. What that really means is:

  • For every field in CustomUser.REQUIRED_FIELDS plus CustomUser.USERNAME_FIELD, there should be a field of the same name in the sign up form;

  • The only exception is the password field, which is populated from three possible different sources: password, password1, or password2. This is to accommodate forms which have duplicated fields for password checking (which you should do anyway).

    When calling create_user, django-signup will use the first available value from those three options, so make sure that, if you have more than one password field, the values match. Ensure that with a clean_* method on the form, as shown below.

    The drawback of this approach is that you have to call your password fields password{,1,2} instead of, say, pw or anything else.

Implementation

For the user model described above, this form might look like the following:

from django import forms
from your_app.models import CustomUser

class UserSignUpForm(forms.Form):
    email = forms.EmailField()
    password1 = forms.CharField(widget=forms.PasswordInput)
    password2 = forms.CharField(widget=forms.PasswordInput)

    def clean_email(self):
        email = self.cleaned_data['email'].strip()
        try:
            CustomUser.objects.get(email__iexact=email)
            raise forms.ValidationError('email already exists')
        except CustomUser.DoesNotExist:
            return email

    def clean_password2(self):
        pw1 = self.cleaned_data.get('password1')
        pw2 = self.cleaned_data.get('password2')
        if pw1 and pw2 and pw1 == pw2:
            return pw2
        raise forms.ValidationError("passwords don't match")

Note that you should implement whatever logic you need to verify your data here. In this case, we’re checking for uniqueness of the email field and that both passwords match. The email field is also going to be checked when the new user is about to be inserted at the database, but by performing our check in the form we’re able to provide the user with a meaningful message about why the signup process didn’t go as expected.

Using the new form

Next, you have to tell django-signup that you want to use this specific form during the registration process. Suppose that the above form is inside the your_app/forms.py file. Then, you have to add the following to your project settings:

SIGNUP_FORM_CLASS = 'your_app.forms.UserSignUpForm'

Table Of Contents

Previous topic

Admin interface

This Page