Django User Model

In this article, we will go over the Django User Model. We can extend it with AbstractUser and AbstractBaseUser, but what options do we have? How can we customize it and how can we use it?

The Django User Model is part of the Django Authentication package. It provides you with a standard model that is used as a backbone for your user accounts. You can find the standard fields here.

Extending the Django User Model

There are various ways to extend the User model with new fields. You might want to do this, when you want to add options to your users, or when you want to split them in groups (for when you have two different types of accounts for example).

Extend the Django user model with AbstractUser (preferred)

With AbstractUser, you can overwrite the standard User model. It will inherit all functions and current fields from the standard User class and you can add anything you would like to this. Here is an example that would be in models.py:

from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.base_user import AbstractBaseUser

class User(AbstractBaseUser):
    is_trailing = models.BooleanField(default=True)
    # add extra fields here

Once you did that, you will also need to let Django know that we want to use that table as the default user table. You can do that with adding the next line to your settings.py file (replace <yourappname> with whatever your app name is.

AUTH_USER_MODEL = 'yourappname.User'

Why this is the preferred method: you keep your database extremely clean as you are not creating any extra unnecessary tables (always keep database normalisation in mind!). Remember that great programmers care much more about the design and architect (that's including the layout of your database), then the actual code. It's way easier to refactor code, then it is to migrate your database. It's very easy to create extra model functions for this as you have your user table in your models.

Alternatively, you could also use the AbstractBaseUser. The difference with the AbstractUser here is that AbstractBaseUser doesn't have the standard fields and functions. In other words, you will have to add all the basic items yourself. For most people the AbstractUser will be the right fit.

Extend the Django user model with an extra model

This works too, though you will not follow the normalisation rules that go for database tables. You will have to create an extra (unnecessary) table with this option. Extending the User model with an extra table is easy to implement though. Simply create the new table and then create a one-to-one field to the User model.

class Profile(models.Model):
    user = models.OneToOneField('auth.User', on_delete=models.cascade)
    # add extra fields here

Using this approach means that you will have to call fields through the User class. Here is an example for in your template:

{% raw %}{{request.user.profile.bio}}{% endraw %}

As you can see, we first get the request, then the user, then the profile model that is attached to it and then the field we need. With the first method we can skip the profile altogether as the fields are in the user model (note that profile is lowercase in this case!).

One thing you might want to consider with this method, is to immediately create your Profile when you create the user. For this, we will have to trigger a function when a User is created. We can do that with Signals. Let's create one for the standard User class:

from django.contrib.auth.models import User

@receiver(post_save, sender=User)
def user_save(sender, instance, **kwargs):
  Profile.objects.create(user=instance)

Remove username from Django authentication

There are many cases were it's actually preferred to have users login with their email address instead of a username. A username is generally unnecessary for private applications. To remove the username, we will have to create a new User model and then assign a different UserManager to it. The UserManager is used to create new users. In this we will have to replace it with a custom one since we will not be creating new users like it is normally done. Here is an example:

class CustomUserManager(BaseUserManager):

    def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
        now = timezone.now()
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, is_staff=is_staff, is_active=True, is_superuser=is_superuser, date_joined=now, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        return self._create_user(email, password, False, False, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        return self._create_user(email, password, True, True,**extra_fields)


class User(AbstractBaseUser):
    first_name = models.CharField(max_length=5000)
    last_name = models.CharField(max_length=5000)
    email = models.EmailField(max_length=5000, unique=True)
    is_staff = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)
    last_login = models.DateTimeField(null=True)
    # any fields you would like to add

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

As you can see, we are using the very bare-bone AbstractBaseUser as we don't need the username field and can't change it with the AbstractUser class. If we would have used the AbstractUser class then we would still have to enter a username everywhere.

Django resources user
Written by Stan Triepels

Stan is professional web developer working mainly with Django and VueJS. With years of experience under the belt, he is comfortable writing about his past mistakes and ongoing learnings.