Manage custom user accounts and profiles for your Django site


  When you develop a web application with Django that requires account management, it is often necessary to customise the default “user” model provided by Django. In this article, we’ll discuss the important elements involved in creating a custom user model and an associated profile model.  

Why a custom user model?

  Django provides a very comprehensive user template, but it may not meet all your needs. For example, you may want to add additional fields such as a profile photo or links to social networks. In these cases, we recommend creating a custom user template.  

Create a customised model for users

  Assuming you already have the classic Django project code base, for example generated with the “django-admin startproject” command, we can add an app (a Django-specific concept) that we name users within the project with the :  
python manage.py startapp
  Next, make sure that the “users” app is referenced in the project’s settings.py file, in the list of apps (INSTALLED_APPS).   For example, in the settings.py file:  
  To create a custom user model, you need to create a class that inherits from the AbstractBaseUser abstract class and the PermissionsMixin “mixin” class (which come from the django.contrib.auth module).   In addition, to accompany your customised User class, you will define a UserManager class which is responsible for creating users and “superusers”. It will inherit from the BaseUserManager base class and implement the create_user and create_superuser methods.   Without going into all the details, here’s an example of the code for this part, which will typically be found in users/models.py in the Django application package:  
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models

# UserManager custom
class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        # code pour créer un user

    def create_superuser(self, email, password=None, **extra_fields):
        # code pour créer un superuser

# User custom
class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
  There is one important thing to do here, from the point of view of the framework, for things to work: Add the parameter AUTH_USER_MODEL to the settings.py file, with the value of the string corresponding to the user account model.   AUTH_USER_MODEL = 'users.User'   If in doubt about the value assigned to this parameter, remember that it is the application label (found in the users/apps.py file) followed by “.” followed by the name of the model, in this case the string “users.User”.  

Create the profile template

  To add additional information to the user account in the database, you can create a profile template. In fact, it’s even recommended. This template will be linked to the user template via a “1 to 1” relationship; to do this, you’ll use a OneToOneField.   Here is an example of how to define a template called Profile for the user profile:  
class Profile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    picture = models.ImageField(upload_to='profile_pics/')
    bio = models.TextField()

    def __str__(self):
        return f"{self.user} profile"
  We’ve added the definition of the special __str__ method that Python offers, which is called in the background every time we use the str() function, to make the display of objects more meaningful, and this will be useful later.  

Database migration

  Don’t forget the essential step of generating the database migration code, using the :  
python manage.py makemigrations users
  The effect of this is, for example:  
Migrations for 'users':
    - Create model User
    - Create model Profile
  Of course, now that we have the migration code, we’ll apply it to migrate the state of our database, using the :  
python manage.py migrate

Test the result

  To test the result of adding these two models, we could complete the code for the UI part of the application, by writing a ‘view’, a ‘form’ and templates, as provided for in the Django framework.   But to test things out straight away, we’re going to use the Django shell, via the following command:  
python manage.py shell
  We can test things in the shell as follows:  

>>> from django.contrib.auth import get_user_model
>>> User = get_user_model()
>>> u = User(email="john.doe@example.com")
>>> u.save()
>>> from users.models import Profile
>>> u_profile = Profile(user=u)
>>> u_profile.save()

>>> print(f"{u} - {u_profile}")
john.doe@example.com - john.doe@example.com profile
  You’ll notice that we haven’t imported the User model with :  
from exampleapp.users.models import User
  We could have. But instead we used the get_user_model() function, provided by the django.contrib.auth module, which returns the class where we need it. And then we use the class. This is actually the recommended method. It ensures that you’re using the correct user template, even if a custom template has been defined. In the background, this function relies on the value referenced in the settings.py file as seen above. So, typically, if you’re writing view code, for the application UI, you’ll write this sort of thing:
from django.contrib.auth import get_user_model

User = get_user_model()

def my_view(request):
    users = User.objects.all()


  In Django, it’s common practice to set up a custom user template and associated profile template for greater flexibility. This allows you to add extra fields and functionality to meet the specific needs of your application. Feel free to customise these templates to suit the needs of your project. You can find the code that accompanies this article in our Github here: https://github.com/ContentGardeningStudio/djangoexampleapp

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top