How To: Create a Custom User using Mixins

Warning

This configuration method is but one of three, and may not make the most sense for your project. Please read Select a Configuration Method for Improved User before continuing, or else follow the instructions in Quickstart: Using Improved User.

The User and AbstractUser classes supplied by the package are not always what you want. In some cases, they may supply fields you do not need or wish for. This tutorial demonstrates how to create User models using the provided mix-in classes, effectively building the model from scratch.

In this tutorial, we will create a new custom User that has an email field and password, but which does not feature either the short_name or full_name fields.

Warning

Not supplying methods for names on the User model will cause problems with Django’s Admin.

Tip

If you’re looking to extend the User model, rather than replace it as shown in this tutorial, use the following steps:

  1. inherit AbstractUser (follow the instructions in Quickstart: Using Improved User to see how)

  2. add new fields as desired

  3. override REQUIRED_FIELDS if necessary (remembering to put 'short_name', 'full_name' in the list)

In an existing app, in the models.py file, we start by importing the tools we need to build the model. We first import classes from Django.

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import gettext_lazy as _

AbstractBaseUser and PermissionsMixin will serve as a base for the User (click the classes in this sentence to see Django’s official documentation on the subject). We also import gettext_lazy() to enable translation of our strings.

We then import mix-in classes from Improved User.

from improved_user.managers import UserManager
from improved_user.model_mixins import DjangoIntegrationMixin, EmailAuthMixin

The DjangoIntegrationMixin class provides fields that allow the model to integrate with Django’s default Authentication Backend as well as a field to allow for integration with Django’s Admin.

The EmailAuthMixin creates an EmailField and sets the field to be used as the username during the authentication process.

The UserManager is a custom model manager that provides the create_user() and create_superuser() methods used in Django.

Danger

Improved Users’ custom UserManager is intended to work with subclasses of EmailAuthMixin, and will likely not work with your User subclass if you are using a different field for your username. You will, in that case, need to create your own UserManager. The source code for Improved Users’ UserManager as well as Django’s BaseUserManager and UserManager would likely prove helpful.

Note

If you wanted to create a User model with a field other than email for username, you would set the USERNAME_FIELD on your User model to the name of the field that should serve as the username. Please take a look at the source of EmailAuthMixin for an example of this.

With all our tools in place, we can now create a User model. We start by creating a class that inherits all of the classes we have imported, and then we tie the UserManager to the new model.

class User(
    DjangoIntegrationMixin, EmailAuthMixin, PermissionsMixin, AbstractBaseUser
):
    """A user created using mix-ins from Django and improved-user

    Note that the lack of name methods will cause errors in the Admin
    """

For good measure, we can specify the name and verbose name of the model, making sure to internationalize the strings. Our full and final models.py file is shown below.

"""A User model created by django-improved-user mixins"""
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import gettext_lazy as _

from improved_user.managers import UserManager
from improved_user.model_mixins import DjangoIntegrationMixin, EmailAuthMixin


class User(
    DjangoIntegrationMixin, EmailAuthMixin, PermissionsMixin, AbstractBaseUser
):
    """A user created using mix-ins from Django and improved-user

    Note that the lack of name methods will cause errors in the Admin
    """

    objects = UserManager()

    class Meta:
        verbose_name = _("user")
        verbose_name_plural = _("users")

Tip

Setting abstract = True in the Meta class would allow the class above to be an AbstractUser model similar to AbstractUser

For all of the classes you may use to create your own User model, please see model_mixins.