Custom User model fields

The default Django User model (i.e. django.contrib.auth.models.User class), uses a minimum set of data fields, that include: username, email, first_name, last_name, date_joined and last_login; in addition to the permission related fields: password, is_superuser, is_staff and is_active.

While these last fields are enough for Django's built-in user functionality, they can fall short if you're expecting to store additional user data (e.g. age, telephone, address). There are two approaches to support additional user data: create a separate model to store additional data and create a user relationship to it (i.e. a User with a ForeignKey) or override the default django.contrib.auth.models.User class to create a custom user class.

Listing 10-14 illustrates the first technique by creating an additional model to store extra user data and creating a relationship to the django.contrib.auth.models.User class.

Listing 10-14. Model with extra user fields related to default Django user model

from django.contrib.auth.models import User
from django.db import models

class UserExtra(models.Model):
    user = models.ForeignKey(User)
    age = models.IntegerField(blank=True,null=True)
    telephone = models.CharField(max_length=15,blank=True,null=True)

The UserExtra model in listing 10-14 functions like any other model with a ForeignKey data type, and as such, has some performance and maintenance implications when used in these circumstances. On the negative side, the user data is distributed in two database tables. One table for User records and another for UserExtra records, which inevitably requires two queries or a join query to obtain all data for a given user -- see Chapter 7 for queries across model relationships. On the positive side, this technique keeps a project's default Django User model class intact requiring no additional configuration or development effort.

Next, let's take a look at the second technique which consists of creating a custom user class, a process that's illustrated in listing 10-15.

Listing 10-15. Custom User model to override default Django User model

# models.py (app registration)
from django.contrib.auth.models import AbstractUser from django.db import models class CoffeehouseUser(AbstractUser): age = models.IntegerField(blank=True,null=True) telephone = models.CharField(max_length=15,blank=True,null=True) # admin.py (app registration) from django.contrib import admin from .models import CoffeehouseUser class CoffeehouseUserAdmin(admin.ModelAdmin): pass admin.site.register(CoffeehouseUser, CoffeehouseUserAdmin) # settings.py AUTH_USER_MODEL = 'registration.CoffeehouseUser'

The first section in listing 10-15 shows the CoffeehouseUser class to be used as the custom user class. Notice the class inherits its behavior from the AbstractUser class which gives it the same fields and behaviors as the default User class (e.g. username, email,etc.). Next, the CoffeehouseUser class declares the age and telephone fields using standard model fields, giving the custom user class two more fields than the default User class.

Because the custom CoffeehouseUser class will override a project's default User class, this means the default django.contrib.auth.models.User class is no longer used. Therefore, you must configure Django to use the custom CoffeehouseUser class anywhere user logic is required.

The second section in listing 10-15 shows the Django admin configuration necessary to access the new custom user class from the Django admin and be able to create, read, update and delete users, just like it's done the the standard django.contrib.auth.models.User model class. Note the next chapter covers Django admin configuration in greater detail.

Finally, the third section in listing 10-15 shows the Django settings.py file with the AUTH_USER_MODEL set to registration.CoffeehouseUser, where registration represents the app name and CoffeehouseUser the custom user model. This last configuration ensures user logic made throughout a project is made on the CoffeehouseUser model and not the default User model.

Once you run the migration operation with this custom user model class and configurations from listing 10-15, you'll see Django project users gain two additional fields.

Caution Custom user model implementations like the one in listing 10-15 should only be done at the outset of a project (i.e. one the first project migration).

Because a user model plays such a central role in managing access to a Django project, you should not attempt to implement custom user models like the one in listing 10-15 midway through a project. Doing so runs the risk of breaking dependencies -- foreign keys -- used by other models to refer to default django.contrib.auth.models.User model records, in addition, this also changes the underlying database table where user data is stored. By implementing a custom user model at the outset of a project, you guarantee any possible model dependencies made on a user are done against custom user records and user data is stored in a single database table from the outset.

In fact, if you plan to use a custom user model, but don't know which new fields to add at the outset, you can create a placeholder user model like the following:

class CoffeehouseUser(AbstractUser):
      pass

This snippet creates a model identical to the default django.contrib.auth.models.User class, but lays the groundwork to create user dependencies on the custom model, while allowing the ability to add fields to the custom model as they're needed with standard migrations like any other model.

Finally, another factor to take into account when using a custom user model -- which isn't obvious in listing 10-15 -- is how to reference a custom user model in other places of a project. When you use the default User class, the statement from django.contrib.auth.models import User is commonplace in models.py and views.py files to reference a user, but with a custom model this reference is no longer applicable.

To support custom user models, Django offers the helper method get_user_model that returns a reference to whatever user model is defined in the AUTH_USER_MODEL variable in settings.py. In this manner, you can use the statement from django.contrib.auth import get_user_model to obtain a reference to a project's user model from anywhere in a project. The next section on authentication back-ends contains an example that uses the get_user_model method.