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? Usesettings.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
.