(Comments)
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 username
, first_name
, last_name
, email
and some other meta data. The best way to add more details is to define a new model with a OneToOneField related to the User model.
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 User
and 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()
The 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
, email
etc, we can specify the field name that can be used to uniquely identify the user with the 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 hello@cowhite.com
Comments