Django Model Constraint Condition Using Field From Inherited Class - Возможно ли это?
Я хотел бы использовать поле из родительского класса в качестве условия ограничения в дочернем классе.
models.py
class ParentClass(object):
...
is_public = models.BooleanField(default=False)
class ChildClass(ParentClass):
...
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
class Meta:
constraints = [
models.CheckConstraint(
check=Q(price__isnull=True) & Q(is_public=True), # <- here
name='price_exists_check',
)
]
Когда я пытаюсь мигрировать, я вижу эту ошибку в моем терминале:
myapp.ChildClass: (models.E016) 'constraints' refers to field 'is_public'
which is not local to model 'ChildClass'.
HINT: This issue may be caused by multi-table inheritance.
Очевидно, почему я вижу эту ошибку (поле is_public
живет в ParentClass
). Мой вопрос заключается в том, что это просто невозможно, или я могу что-то рефакторить?
Какова моя конечная цель?
Не позволять экземпляру ChildClass
is_pulic
изменяться на True
, если price
является null
. Я хотел бы обеспечить это на уровне базы данных.
Есть ли способ, и если да, то что нужно изменить?
Мой вопрос заключается в том, что это просто невозможно, или я могу что-то рефакторить?
Я отследил оригинальный коммит, в котором появилось сообщение об ошибке, которое вы видите, и баг, который он исправлял. Документация по наследованию моделей также полезна для понимания этого.
Вот как я понимаю проблему:
Если вы создаете модель Django, которая наследуется от другой модели, и эта модель не является абстрактной, то Django создает внешний ключ к родительской таблице, а не повторяет все поля из родительской модели в дочерней таблице. Поэтому, когда вы создаете объект ChildClass, это создает строку в таблице ChildClass и в таблице ParentClass.
Вы не можете создать ограничение CHECK, которое ссылается на несколько таблиц. (Насколько я знаю.) Поэтому Django запрещает вам создавать это ограничение.
Таким образом, у вас есть следующие варианты:
Усиливайте его на уровне ORM. В методе clean() проверьте, выполнено ли ваше ограничение. ( Документация.) Это не предотвратит нарушение ограничения, если программа, не относящаяся к Django, модифицирует базу данных.
.Сделать родительский класс абстрактным. Вы уже сказали, что это не выполнимо.
Сделайте третий класс, от которого наследуются оба класса. Создайте базовый класс следующим образом:
------------- | BaseClass | ------------- | | V V --------------- -------------- | ParentClass | | ChildClass | --------------- --------------
Сделайте BaseClass абстрактным, а ParentClass и ChildClass конкретными. Это позволит вам использовать ограничение, так как данные ChildClass находятся в одной таблице.