Django Models - попытка получить "лучшее из двух миров", когда дело доходит до копирования модели против ее подклассификации
Допустим, у меня есть базовый класс (модель Django) под названием Character, который выглядит примерно так
class Character(models.Model):
strength = models.blabla
dex = models.blabla
...
Я могу установить его атрибуты и подключить к Admin, и все будет прекрасно.
Затем я решаю, что мне нужна модель неигрового персонажа, в которой есть все, что есть в модели персонажа, плюс новое поле или два. Я могу представить как минимум два способа сделать это, каждый из которых имеет свои плюсы и минусы.
Вариант 1:
# The basic obvious stupid-simple answer is just to copy the model and add the fields
class NonPlayerCharacter(models.Model):
strength = models.blabla
dex = models.blabla
...
faction = models.blabla
Плюсы: Все очень просто и легко управляется, а если в будущем модели будут расходиться, это тоже не составит труда.
Минусы: Очевидное дублирование кода и синхронизация универсальных изменений. Если я меняю стат или добавляю метод в одном, мне приходится дублировать его в другом. Если я добавлю еще один тип персонажа, например мобов, то придется втрое увеличить расходы на поддержание синхронизации необходимых частей.
Вариант 2:
# The next most obvious solution is to subclass Character
class NonPlayerCharacter(Character):
faction = models.blabla
Плюсы: Мне не нужно беспокоиться о синхронизации классов, если я что-то добавляю или изменяю. Каждый из них занимается только своими новыми атрибутами и методами.
Минусы: Везде, где я запрашиваю Character, по умолчанию также будут выведены все подклассы Character. Я (в некоторой степени) знаю, как отфильтровать это в каждом конкретном запросе, но было бы здорово, если бы Character.objects просто получал персонажей, а все остальное оставлял на усмотрение запросов для конкретной модели/подкласса.
Есть ли удобный метод, позволяющий получить лучшее из обоих миров, не фильтруя Character каждый раз, или я просто прошу чего-то неразумного?
Обычно вы можете сделать абстрактную базовую модель, например:
class BaseCharacter(models.Model):
strength = models.blabla
dex = models.blabla
…
class Meta:
abstract = True
class Character(BaseCharacter):
pass
class NonPlayerCharacter(BaseCharacter):
faction = models.blabla