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 запрещает вам создавать это ограничение.

Таким образом, у вас есть следующие варианты:

  1. Усиливайте его на уровне ORM. В методе clean() проверьте, выполнено ли ваше ограничение. ( Документация.) Это не предотвратит нарушение ограничения, если программа, не относящаяся к Django, модифицирует базу данных.

    .
  2. Сделать родительский класс абстрактным. Вы уже сказали, что это не выполнимо.

  3. Сделайте третий класс, от которого наследуются оба класса. Создайте базовый класс следующим образом:

                -------------
                | BaseClass |
                -------------
                |           |
                V           V
    ---------------       --------------
    | ParentClass |       | ChildClass |
    ---------------       --------------
    

    Сделайте BaseClass абстрактным, а ParentClass и ChildClass конкретными. Это позволит вам использовать ограничение, так как данные ChildClass находятся в одной таблице.

Вернуться на верх