Django AllAuth Chapter 5 - Extending Django AllAuth user model with custom fields
Andrés Álvarez Iglesias
Posted on August 13, 2024
NOTE: This article was initially posted on my Substack, at https://andresalvareziglesias.substack.com/
This is the last chapter of this Django AllAuth series of posts. In these five chapters we have discovered a little piece of wonder, a really helpful Django component to handle all our authentication needs. In this chapter we are going to learn how to extend the basic Django user model to add custom fields.
List of chapters
- Chapter 1 - The All-in-one solution for Auth in Django
- Chapter 2 - How to install and configure Django AllAuth
- Chapter 3 - Social login with Django AllAuth
- Chapter 4 - Customizing Django AllAuth UI
- Chapter 5 - Extending Django AllAuth user model with custom fields ←This one!
Django user model
AllAuth uses the standard Django user model, plus some extra tables to handle social login and login tokens. In Django 5, the user model is located in the django.contrib.auth package, and has a bunch of predefined fields, as you can read in the official doc:
Sometimes, this is not enough for our project. Django allows you to create custom User tables and User managers, to handle the needs of every project.
We are going to create a custom User table and a custom UserManager to handle our login and register processes.
Creating a custom User table
Open models.py in our sample project an write a code like this:
class MyCustomUser(AbstractBaseUser):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
timezone = models.CharField(max_length=30, default='UTC')
is_custom = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = MyCustomUserManager()
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
@property
def is_utc(self):
return self.timezone == 'UTC'
We can define a new User model extending from Django's AbstractBaseUser model. In this new model we can add all fields or custom properties that we need.
These lines are important:
objects = MyCustomUserManager()
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
With these lines we are linking the user model with our custom UserManager, and we are also defining the field acting as a unique "username".
Remember to register the new model in admin.py to manage it from the Django admin tool.
from django.contrib import admin
from .models import MyCustomUser
admin.site.register(MyCustomUser)
Creating a custom User manager
Open again models.py in our sample project (or generate another file for the custom UserManager if you want) an write a code like this:
class MyCustomUserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(
email=email,
password=password,
)
user.is_admin = True
user.is_staff = True
user.save(using=self._db)
return user
In this example we are extending BaseUserManager to create our custom UserManager. It creates our new users, and fills the custom fields as we expect.
We defined before the UserManager for our custom User model, so Django knows what class to use during new user creation.
Using the custom User manager and model
In the settings file of our project we can set the current user model for our project with:
# Set custom user model as the active one
AUTH_USER_MODEL = 'demo.MyCustomUser'
# Configure AllAuth username related management, because we are
# using the e-mail as username. See:
# https://docs.allauth.org/en/latest/account/advanced.html
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
With just this small change (and the required DB migration, as usual), we can start to create users with AllAuth signup views to see our shiny custom UserManager and its model in action. Quick and easy.
We are also disabling the AllAuth username related management, because we are using the e-mail as username in this example.
And that's the end... or not?
We have reached the last chapter on this AllAuth series. AllAuth is a wonderful library to handle the authentication in our apps, and makes it especially easy to work with social logins, thanks to its large list of predefined integrations.
This is the last chapter of the series, but I will revisit AllAuth in future posts. Thanks for reading and happy coding!
About the list
Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise... with the fingers crossed), like:
- Software architecture
- Programming environments
- Linux operating system
- Etc.
If you found some interesting technology, programming language or whatever, please, let me know! I'm always open to learning something new!
About the author
I'm Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I'm also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!
Posted on August 13, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
August 13, 2024