Ответ
В Django существует три основных способа наследования моделей, каждый из которых решает свою задачу.
1. Абстрактные базовые классы (Abstract base classes)
Это основной способ избежать дублирования кода (принцип DRY). Вы создаете базовую модель с общими полями и методами, а затем указываете, что она абстрактная. Django не создает для нее отдельную таблицу в базе данных.
- Как использовать: Добавить
abstract = Trueв мета-класс модели. - Когда использовать: Когда нужно вынести общие поля (
created_at,updated_atи т.п.) в несколько дочерних моделей.
Пример:
from django.db import models
class TimeStampedModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
# TimeStampedModel не будет иметь своей таблицы в БД
class Post(TimeStampedModel):
title = models.CharField(max_length=200)
class Comment(TimeStampedModel):
text = models.TextField()
2. Мульти-табличное наследование (Multi-table inheritance)
При этом подходе для каждой модели в иерархии (и для родительской, и для дочерней) создается своя таблица в БД. Django автоматически создает связь OneToOneField от дочерней модели к родительской.
- Как использовать: Просто унаследовать одну конкретную модель от другой.
- Когда использовать: Когда каждая дочерняя модель является специализированным видом родительской и имеет свои уникальные поля. Это реализует классический полиморфизм.
Пример:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
# Будут созданы таблицы для Place и для Restaurant
class Restaurant(Place):
serves_pizza = models.BooleanField(default=False)
3. Прокси-модели (Proxy models)
Прокси-модели позволяют изменить поведение модели на уровне Python (например, добавить новые методы, изменить стандартный менеджер), не меняя ее поля и структуру в базе данных. Для прокси-модели не создается новая таблица.
- Как использовать: Добавить
proxy = Trueв мета-класс модели. - Когда использовать: Когда нужно предоставить разный интерфейс (методы, менеджеры) для одной и той же таблицы в БД.
Пример:
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def get_full_name(self):
return f"{self.first_name} {self.last_name}"
# MyPerson работает с той же таблицей, что и Person, но имеет дополнительный метод