BaseModel w Django

Czasami gdy tworzymy model w Django, chcemy aby niektóre kolumny pojawiały się w każdej tabeli bazy danych. Dobrym przykładem (a zarazem dobrą praktyką) jest dodawanie pól, które reprezentują czas stworzenia oraz modyfikacji dla każdego wiersza w tabeli. Bez użycia bazowych klas abstrakcyjnych, byśmy musieli przepisać ten sam kod, dla każdego modelu w naszej aplikacji Django.

A czym dokładnie są wspomniane klasy?
Tutaj przetłumaczona informacja o tym z dokumentacji Django:

Bazowe klasy abstrakcyjne są użytecznie, gdy chcemy umieścić informacje, które są współdzielone przez kilka modeli. Piszesz swój kod i dodajesz abstract=True w Meta class. Model ten nie będzie użyty podczas tworzenia nowych tabel baz danych. W zamian, kiedy tego typu model będzie użyty jako klasa bazowa dla innych modeli, jej pola będą dodane do klasy pochodnej.

Całkiem spoko, nasza klasa nie zostanie dodana jako nowa tabela bazy danych.

Stwórzmy BaseModel

W naszym pliku models.py chcemy stworzyć klasę BaseModel, która będzie przechowywać dane współdzielone przez wszystkie tabele bazy danych. Nasz BaseModel będzie dziedziczyć z domyślnego modelu django.db.models.Model. Naszym celem z następującym kawałkiem kodu będzie dodanie pól odpowiedzialnych za przechowywanie informacji o czasie stworzenia i edycji w formie DateTimeField.

from django.db import models


class BaseModel(models.Model):
    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        db_index=True
    )

    class Meta:
        abstract = True

Warto zauważyć, że klasa Meta posiada ustawioną wartość abstract = True. Bez tego nasz BaseModel pojawiłby się jako normalna tabela w naszej aplikacji Django.

Czas na użycie BaseModel

Teraz, gdy stworzyliśmy nasz model, powinniśmy go zaimplementować w pozostałych tabelach bazy. Jest to dość proste - jedyną rzeczą którą trzeba zrobić, to zamiana django.db.models.Model na nasz BaseModel, dla każdego modelu który będziemy tworzyć. Poniżej zaprezentowałem przykład modelu User, który korzysta z naszego BaseModel.

class User(BaseModel):
    name = models.CharField(
        max_length=30
    )

Gdy zmigrujemy nasze modele, User będzie posiadał następujące kolumny: