Creating A Custom User Model In Django

Creating A Custom User Model In Django

ยท

4 min read

from django.contrib.auth.models import User

The Python framework Django, has a built in user model as shown above which comes with a number of features making development faster and easier, however this model has a number of shortcomings which would be briefly discussed in this article.

The username field is case-sensitive

Even though the username field is unique it is also case sensitive which makes it not entirely unique after all and this is a problem. The model would treat the username Jane_Doe and JANE_DOE as two separate usernames and this provides a poor user experience as people wouldn't expect Jane_Doe and JANE_DOE to be two separate usernames, also If your app offers social features that rely on the username supplying a public URL, this can be a security risk.

The email field is not unique

More than one user can have the same email address associated with their account. Django's inbuilt user model would identify the email and as two separate emails, even though by convention all email characters should be in lowercase, it would be a bad user experience to allow a user register an email with uppercase characters also to recover a password the email address is utilized by default. If more than one user has the same email address, the password reset for all accounts will be initiated, and the user will receive an email for each active account.

It uses the username as the login parameter

You would want the user login to be done with the email and not the username. People tend to use entirely different usernames or usernames with slight differences for different programs but definitely one email for most or all of those accounts, it'll be easier for that user to remember his/her email than username.

There are many more reasons you wouldn't want to use Django's default user model if you are developing your program for production, try it out yourself and you'll find a few more. Now it's time we create our custom user model.

Step 1: Creating the user model

In your user's app models.py file, we inherit from the AbstractBaseUser and the BaseUserManager. Basically, they are classes we could use to extend the generic Django user model and create a custom user model.

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

class Account(AbstractBaseUser):
    email = models.EmailField(verbose_name="email", max_length=60, unique=True)
    username = models.CICharField(max_length=30, unique=True)
    date_joined = models.DateTimeField(verbose_name='date_joined', auto_now_add=True)
    last_login = models.DateTimeField(verbose_name='last_login', auto_now=True)
    is_admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']
    objects = MyAccountManager()

    def __str__(self):
        return self.username

    def has_perm(self, perm, obj=None):
        return self.is_admin

    def has_module_perms(self, app_label):
        return True

In the code snippet above when creating a custom user model these fields are required, additional fields of choice could be added if wanted like first_name and last_name. You need to set the username field USERNAME_FIELD = 'email' to whatever parameter you want the user to be able to login with, this actually bothers me and I feel wasn't very intuitive of Django, it might be a little confusing but that is how it is. The required fields REQUIRED_FIELDS = ['username'] literally means fields that must be provided.

Step 2: Create the User model manager

If you override the default user model in Django, you will need to override the create_user() and create_superuser(). Basically we are defining what we want to happen when a new user is created and when a new superuser is created, you should read the docs for more information.

class MyAccountManager(BaseUserManager):
    def create_user(self, email, username, password=None):
        if not email:
            return ValueError("Users must have an email address")
        if not username:
            return ValueError("Users must have a username")

        user = self.model(
            email=self.normalize_email(email).lower(),
            username=username,
            password = password,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, password):
        user = self.create_user(
            email=self.normalize_email(email),
            password = password,
            username = username,
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

Step 3: Setting the model you just created

In the settings.py file of your project's base directory set AUTH_USER_MODEL = 'account.Account', here account is the name of the user app and Account is the model we just created. We are overriding the default user model Django provides and making reference to the one we just built.

Step 4: We migrate

Finally, you need to go to your terminal and the location of the current working file, activating the required virtual environment and run python manage.py makemigrations and python manage.py migrate. The python manage.py makemigrations prepares the created model to be converted to sql format and the python manage.py migrate commit those changes. You can now createsuperuser and login the admin page.

Conclusion

The Django default user model is very useful and would save you a lot of code and time but you would want the option to be able to make alterations to certain fields and be able to manipulate the behaviour of your models to suit the needs of your program so creating a custom user model would be better than using the default user model and we've just learnt how to create it.

Thank you for reading and I hope you find this article useful and informative. ๐Ÿ˜Š