DEV Community

Andrés Álvarez Iglesias
Andrés Álvarez Iglesias

Posted on

Django AllAuth Chapter 5 - Extending Django AllAuth user model with custom fields

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 AllAuth Chapter 5 - Extending Django AllAuth user model with custom fields

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'
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)