Django Best Practices: Referencing the User Model

Updated

Table of Contents

Django has a powerful, built-in user authentication system that makes it quick and easy to add login, logout, and signup functionality to a website.

But how should a Django developer reference a User? The official Django docs list three separate ways:

In this post we will review why you might need to reference the User model and the pros/cons of each of these three approaches.

Option 1: User

Let's assume we have a basic models.py file for a Blog. Here's what it might look like:

# blog/models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=50)
    body = models.TextField()

Now what if we wanted to add an author field so that we could track which user created a blog post and later add permissions on top of that? The default way is to access User directly, which is the built-in Django model that provides us with username, email, password, first_name, and last_name fields.

# blog/models.py
from django.db import models
from django.contrib.auth.models import User # new

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)  # new
    title = models.CharField(max_length=50)
    body = models.TextField()

Pretty straightforward, no? The problem is that it is common--indeed recommended in the official docs--to use a custom user model instead. Instead of referring to User directly, there are two different ways to reference the user model.

Option 2: AUTH_USER_MODEL

AUTH_USER_MODEL is the recommended approach when referring to a user model in a models.py file.

If you've already created a custom user model in an app called accounts (though this could also be called users or anything else, really), you'd reference it in your settings.py file as follows:

# settings.py
AUTH_USER_MODEL = "accounts.CustomUser"

Then in your Blog models.py file the code would look like this:

# blog/models.py
from django.conf import settings  # new
from django.db import models

class Post(models.Model):
    author = models.ForeignKey(
      settings.AUTH_USER_MODEL,  # new
      on_delete=models.CASCADE
    )
    title = models.CharField(max_length=50)
    body = models.TextField()

Python imports can be leaky and since AUTH_USER_MODEL uses a string reference it is part of Django's initialization process. This avoids a number of less obvious issues that can creep up down the line using Signals and other techniques.

Option 3: get_user_model

The other way to reference the user model is via get_user_model which returns the currently active user model: either a custom user model specified in AUTH_USER_MODEL or else the default built-in User.

The code would look as follows:

# settings.py
AUTH_USER_MODEL = "accounts.CustomUser"

Then in a non-models.py file, so let's say a views.py that listed all your users, you'd use it like this:

# accounts/views.py
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView

User = get_user_model()

class UserListView(LoginRequiredMixin, ListView):
    model = User
    template_name = "user_detail.html"

Up until the release of Django 1.11, get_user_model was not called at import time--meaning it would not always work correctly--however that has since been changed. It is therefore safe to use. And in fact for non models.py files, it is a better approach than settings.AUTH_USER_MODEL.

Conclusion

User authentication is tricky and having a built-in solution thanks to Django saves us as developers a ton of work. That said, to future-proof your code it is best to reference the user model rather than directly refer to User. Of the two available options the following advice should hold:

  • models.py file? Use settings.AUTH_USER_MODEL.
  • anything else? Use get_user_model().

Note: Special thanks to Jeff Triplett for expanding the initial explanation and pointing out why settings.AUTH_USER_MODEL is a better approach for models.py.