How to use Base Model (Inheritance) in Django?

The TLDR answer:

Once you start creating a serious project in Django you would want to add created_at and updated_at to most of the models. That's when you realise you are not following the Don't Repeat Yourself(DRY) principle by copy-pasting the same field over and over. On top of it, few times your junior developer misses adding the field and it might slip through the review and would be caught in production after someone wanted to check the created_at data.

How do you solve these problems?

Inheritance of Django models. Yes, that is the best and safest solution which I have come across.

from django.db import models


class Organisation(models.Model):
    name = models.CharField("name of the organisation", max_length=200)
    created_at = models.DateTimeField(auto_now_add=True) ) # DRY not followed
    updated_at = models.DateTimeField(auto_now=True) ) # DRY not followed


class Profile(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True) # DRY not followed
    updated_at = models.DateTimeField(auto_now=True) ) # DRY not followed
    bio = models.CharField("bio of the user", max_length=500)
not so good way 
from django.db import models

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        abstract = True



class Organisation(BaseModel):
    name = models.CharField("name of the organisation", max_length=200)

class Profile(BaseModel):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    bio = models.CharField("bio of the user", max_length=500)
Better and cleaner way

Unknowingly you have been using this logic. Whenever you inherit any Django models.Model, you also inherit field id. To verify this I would recommend you to explore the parent class models.Model. You would find id field as an auto-incremented primary key field which gets added to all the tables you create. Now when we are using the BaseModel concept, we are just extending it using custom logic, catered for your use case.

One new thing you would notice is abstract = True , using this flag we tell Django that BaseModel is an abstract models class, i.e. no table would be created if someone just used BaseModel. Rather one has to inherit BaseModel to have Django migration create a table which would have all the fields of BaseModel along with the fields of the model which is inheriting from it.