Django's authentication system is highly customizable. Yet the default authentication is good enough for most use cases. However we might need to customize to suite our needs. We will explore the various methods of customization.
The default Django's user model is
django.contrib.auth.model.User and it stores
For example let us define model called Profile which can store some extra details of the user.
from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) department = models.CharField(max_length=100) date_of_birth = models.DateField()
We can now add additional data of the user using the
Profile model. We can add the data to the model at the time of registration, something like this.
def register(request): # Validate the user registration data if userForm.is_valid(): email = userForm.cleaned_data['email'] username = userForm.cleaned_data['username'] password = userForm.cleaned_data['password'] user = User.objects.create_user(email=email, username=username, password=password) # Then save the profile details dob = userForm.cleaned_data['date_of_birth'] department = userForm.cleaned_data['department'] profile = Profile.objects.create(user=user, date_of_birth=dob, department=department)
While this is ok, it is possible that only the
User model is saved and creation of
Profile object fails for some reason. This can fail the integrity of the data. Such problems can be avoided with the use of atomic transactions. Django's transactions allow us to perform all the database activities as an atomic transaction i.e., either all the database operations are complete or none of them is saved. This will make our system consistent.
Django's transactions are easy to use. We can use the
transaction.atomic() context manager with
with and perform all the database operations withing the same block. The implementation will make things more clear.
from django.db import transaction, DatabaseError def register(request): # Validate the user registration data if userForm.is_valid(): email = userForm.cleaned_data['email'] username = userForm.cleaned_data['username'] password = userForm.cleaned_data['password'] dob = userForm.cleaned_data['date_of_birth'] department = userForm.cleaned_data['department'] try: with transaction.atomic(): # All the database operations within this block are part of the transaction user = User.objects.create_user(email=email, username=username, password=password) profile = Profile.objects.create(user=user, date_of_birth=dob, department=department) except DatabaseError: # The transaction has failed. Handle appropriately pass
With this piece of code we can be sure that either both the models
Profile are saved to the database or none is saved in which case we catch the error and handle it appropriately. Transactions are life savers when we want to ensure integrity in our applications.
Django allows us to use a custom model to represent a user. To do this, we can extend the
django.contrib.auth.models.AbstractUser abstract model.
from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): department = models.CharField(max_length=100) date_of_birth = models.DateField()
AbstractUser model already defines the required fields like username, email, password etc., attributes and methods. We only need to define the additional fields that we need. But we don't always need to extend the
AbstractUser. Instead we can use any model that we want. Once we are ready with our model set the value of
AUTH_USER_MODEL in the project settings to the class name (string) of the user model.
AUTH_USER_MODEL = 'myapp.models.CustomUser'
With this setting Django recognizes the model used to represent the users of the application. We can use the regular of creating user model (don't forget to use the
set_password() method to set a user's password) or we can create a model manager.
One more thing to keep in mind is how to we use the user model in our apps. If we are building an app that depends on the user model i.e., has a model that references user model, it cannot be used if the project uses a custom user model. To address this issue, we have to use the
AUTH_USER_MODEL setting to specify the model.
# Use the following way to reference a user model user = models.ForeignKey( settings.AUTH_USER_MODEL )
By this, our Django applications references the user model what ever the project uses making our application generic. While this is enough for most of the use cases, Django also provides more ways to customize the model and keep our applications generic. For example, even though we do not have the preferred fields like
USERNAME_FIELD. Visit the section specifying a custom user model for more information.
We develop web applications to our customers using python/django/angular.
Contact us at firstname.lastname@example.org