# Eliminate boredom and reduce tension with Abstract models in Django

Working with Django, we get lost in love, wonder and praise as we discover neat stuffs we can work with, one of such being abstract models.

I've come to use UUIDs in all my django models by default. With time, I've wanted to make things easier for myself and try to leverage abstraction in OOP to ensure my models could automatically have uuid fields without having to explicitly specify them.

As usual, we'll begin with a problem:

## The problem
Isaac from [my previous article](https://blog.lordsarcastic.dev/to-mock-or-not-to-mock) who as usual loves shady deals has been leveraged with a small project from LEFTR (LEague of Fundamental Thieves and Robbers). They want a managed record of their members who have been caught by the law and the police agent involved in bringing them to book. They call the project, *Ole*.

Isaac then churned the following elegant code in the models.py of *Ole* project:

```
import uuid

from django.db import models
from django.template.defaultfilters import slugify

class Police(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4)
    first_name = models.CharField(max_length=32)
    last_name = models.CharField(max_length=32)
    nickname = models.CharField(max_length=32)
    avatar = models.ImageField(upload_to='police')
    slug = models.Slugfield(blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.nickname

    def save(self, *args, **kwargs):
        identifier = f"{self.first_name} {self.last_name}"
        self.slug = slugify(identifier)
        return super().save(*args, **kwargs)


class Thief(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4)
    first_name = models.CharField(max_length=32)
    last_name = models.CharField(max_length=32)
    street_name = models.CharField(max_length=32)
    avatar = models.ImageField(upload_to='thief')
    slug = models.Slugfield(blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.street_name

    def save(self, *args, **kwargs):
        identifier = f"{self.first_name} {self.last_name}"
        self.slug = slugify(identifier)
        return super().save(*args, **kwargs)
```

That wasn't too bad was it?

## The issue
Isaac feels this code should be improved since it's his first real project. In addition, he might never make it outside the room he'll present the code in, to the thieves. So, he's particular about not dying while decrepit code stays on his Github account.

## The actual issue
As you can see, there are lots of fields that both Thief and Police share. Normally, under OOP circumstances, you'd be reeling with "Why isn't Isaac doing some inheritance here?".
Thing is, we're dealing with databases here and this is Django and not largely-unopinionated frameworks like Express or Flask where you can likely do what you want. This means you've got to do it in an intuitive and Django-friendly manner.

## How to do?
Here comes abstract models. What we'll do is to extract common functionality into a model and tag it as abstract, meaning it is not concrete enough to be a table in the database but it's solid enough to be a structure for other tables.

So, Isaac defines a `BaseModel` like so:

```
class BaseModel(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4)
    first_name = models.CharField(max_length=32)
    last_name = models.CharField(max_length=32)
    slug = models.Slugfield(blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    def save(self, *args, **kwargs):
        identifier = f"{self.first_name} {self.last_name}"
        self.slug = slugify(identifier)
        return super().save(*args, **kwargs)

    class Meta:
        abstract = True
```

And then reworks the other models to look like so:

```
class Police(BaseModel):
    nickname = models.CharField(max_length=32)
    avatar = models.ImageField(upload_to='police')

    def __str__(self):
        return self.nickname


class Thief(BaseModel):
    street_name = models.CharField(max_length=32)
    avatar = models.ImageField(upload_to='thief')

    def __str__(self):
        return self.street_name
```

## Let's explain
The `BaseModel` is basically inheritance at work. We extract common functionalities in both `Thief` and `Police` models and make it a parent class `BaseModel`. Since we don't want a table to be created for `BaseModel`, we add a `Meta` subclass and add the `abstract = True` attribute.

If `abstract = True` is omitted, we'll be having three tables in our database when we run `python manage.py makemigrations`: One for `Thief`, one for `Police` and one for `BaseModel` and that's not what we want. There are cases where you might want that though.

As you can see, all methods of the parent class are inherited by the children classes.

## I am your saviour
There, little children, you can rework your abandoned projects to look more elegant with abstract models, especially in stuffs such as UUID usage across all models or even timestamps.

## May the sublime force
be with you.

Photo credits: [Maksim Shutov](https://unsplash.com/@maksimshutov?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/absract?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
  
