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
plusCustomUser.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
, orpassword2
. 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 aclean_*
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'