DEV Community

Will Vincent for Learn Django

Posted on • Originally published at learndjango.com

Django Best Practices: Referencing the User Model

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 the User model? The official Django docs list three separate ways:

  • User
  • AUTH_USER_MODEL
  • get_user_model()

But I find the explanation given to be incomplete. So in this post we will review why you might need to reference the User model and the pros/cons of each approach.

Option 1: User

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

# models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=50)
    body = models.TextField()
Enter fullscreen mode Exit fullscreen mode

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.

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

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=50)
    body = models.TextField()
Enter fullscreen mode Exit fullscreen mode

Pretty straightforward, no?

The problem is that we should always use a custom user model for new projects. The official docs even say so.

But if we have a custom user model, we cannot refer to it as User so how do we reference it? It turns out there are two different ways.

Option 2: AUTH_USER_MODEL

The first--and until recently best--way to reference the custom user model was via AUTH_USER_MODEL.

To add a custom user to a new Django project you need to create a new user model and then set it as such in your settings.py file. I wrote a separate post on how to do this.

But the takeaway is that if we made a users app, a CustomUser model within it, then to override the default User model in our settings.py file we would do the following.

# settings.py
AUTH_USER_MODEL = `users.CustomUser`
Enter fullscreen mode Exit fullscreen mode

In our Blog models.py file the code would look like this:

from django.conf import settings
from django.db import models

class Post(models.Model):
    author = models.ForeignKey(
      settings.AUTH_USER_MODEL,
      on_delete=models.CASCADE
    )
    title = models.CharField(max_length=50)
    body = models.TextField()
Enter fullscreen mode Exit fullscreen mode

Using settings we pass the AUTH_USER_MODEL as a string into our model.

Option 3: get_user_model

A third way to access the user model is via get_user_model. 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.

The code would look as follows:

# settings.py
AUTH_USER_MODEL = `users.CustomUser`
Enter fullscreen mode Exit fullscreen mode

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

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

class Post(models.Model):
    author = models.ForeignKey(
      get_user_model(),
      on_delete=models.CASCADE
    )
    title = models.CharField(max_length=50)
    body = models.TextField()
Enter fullscreen mode Exit fullscreen mode

get_user_model() will return the currently active user model: either a custom user model if specified or else User. It is therefore a cleaner approach, in my opinion, because AUTH_USER_MODEL only works if a custom user model is set.

Conclusion

The takeaway is that working with User models is tricky in any web framework. Django has a robust user authentication system but given that many projects use a custom user model instead, the best approach when you want to refer to the current user model--of the three available--is to just always use get_user_model.

Top comments (0)