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 :ref:`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: .. code-block:: python 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: .. code-block:: python 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. .. _dj-custom-user-models: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model .. _dj-user-creation_form: https://docs.djangoproject.com/en/dev/topics/auth/default/#django.contrib.auth.forms.UserCreationForm 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: .. code-block:: python SIGNUP_FORM_CLASS = 'your_app.forms.UserSignUpForm'