Extending User Class


Extending User Class Author: Mohammad Amaan Abbasi | Oct. 23, 2018

Getting Started


A guide on extending Django’s built in User class. Extending the User class can be headache, not because there is no solution but because there are a lot of solutions to it.

It gets difficult for beginners for them to choose which one is addressing there particular problem.

Most of the time, you just want to add more fields to the User model. What I found is the easiest one is to use One-To-One link with the user Model (profile) along with Django built signals functionality.

Don’t worry if you don’t understand Django signals. I will explain them later in the post.

Let’s get started with the code: Here I have created a class Profile with some example fields and have associated it with the User class.

from django.db import models
from django.conf import settings

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    address = models.CharField(max_length=200, null=True, blank=True)
    bank_id = models.CharField(max_length=200, null=True, blank=True)   

def __str__(self):
    return self.user.username

Nothing special here.

However, objects for this model will not be auto-created. To check it you can do the following (optional): Create a user in Django admin, after that query the profile for the user. You will get :

    RelatedObjectDoesNotExist 
    User has no profile.

Or you can manually check the data-base for the profile table, no record will be there.

We can solve this problem by using the Django’s set of built-in signals that let user code get notified by Django itself of certain actions.

More specifically we will use the:

django.db.models.signals.post_save signal.

Post_Save signal is triggered when a model is saved and that is exactly what we want.

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User

@receiver(post_save, sender=User)
def add_to_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance) 

Let’s break it down.

@receiver(post_save, sender=User)

This line of code will execute whenever the sender i.e the User model instance will be saved. The first argument is the type of signal and the second one is the model name.

Finally, we write a function that creates the profile object For the given user.

Go back to the Django admin create a user and then check the database for the profiles table.

A question can come to your mind that where should I put that code???

You can put it in the views.py file but it is not suitable for production.

Since Django 1.7, the official documentation suggests us to write our signals functions in a different file (i.e. signals.py) and connect them with the signals in the apps.py file of our app. Here we have an example:

signals.py

def signal_post_save(sender, **kwargs):
   print("printing a message...")

app.py

from django.apps import AppConfig
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from .signals import signal_post_save

class MyAPPConfig(AppConfig):
   name = 'blog'
   verbose_name = _('My Blog')

   def ready(self):
       myccl = self.get_model('User')
       post_save.connect(signal_post_save, sender=myccl, dispatch_uid="my_unique_identifier")

Summary

We learned how we can use django signals to extend user class.