Ссылка на внешний ключ дочернего класса в базовой абстрактной модели

Я пытаюсь получить доступ к внешнему ключу дочерней модели в базовой абстрактной модели, чтобы не повторять внешний ключ в каждой из дочерних моделей.

Вот мой код:

class BaseModel(models.Model):
    child_field = models.ForeignKey(to='child_class_either_ModelA_OR_ModelB')

    class Meta:
        abstract = True


class ModelA(BaseModel):
    ....

class ModelB(BaseModel):
    ....

Я хочу ссылаться на дочернюю модель в базовой абстрактной модели.

Есть ли способ использовать дочернюю модель в базовой модели?

Поскольку поля в абстрактном BaseModel будут наследоваться, то мы могли бы иметь ModelA.child_field, который ссылается на себя (ModelA) и ModelB.child_field, который ссылается на себя (ModelB), объявив ForeignKey, который ссылается на себя, как задокументировано здесь:

Для создания рекурсивного отношения - объекта, который имеет отношения "многие-к-одному" с самим собой - используйте models.ForeignKey('self', on_delete=models.CASCADE).

class BaseModel(models.Model):
    child_field = models.ForeignKey(to='self', on_delete=models.CASCADE, null=True)

    class Meta:
        abstract = True


class ModelA(BaseModel):
    field_a = models.CharField(max_length=200)


class ModelB(BaseModel):
    field_b = models.CharField(max_length=200)
>>> from my_app.models import *
>>> 
>>> model_a_1 = ModelA.objects.create(field_a="Value 1")
>>> model_a_2 = ModelA.objects.create(field_a="Value 2", child_field=model_a_1)
>>> ModelA.objects.values()
<QuerySet [{'id': 1, 'child_field_id': None, 'field_a': 'Value 1'}, {'id': 2, 'child_field_id': 1, 'field_a': 'Value 2'}]>
>>> 
>>> model_b_3 = ModelB.objects.create(field_b="Value 3")
>>> model_b_4 = ModelB.objects.create(field_b="Value 4", child_field=model_b_3)
>>> ModelB.objects.values()
<QuerySet [{'id': 1, 'child_field_id': None, 'field_b': 'Value 3'}, {'id': 2, 'child_field_id': 1, 'field_b': 'Value 4'}]>

Перекрестные ссылки между различными дочерними моделями будут неудачными, например, ModelA связан с ModelB.

>>> model_a_5 = ModelA.objects.create(field_a="Value 5", child_field=model_b_4)
Traceback (most recent call last):
    raise ValueError(
ValueError: Cannot assign "<ModelB: ModelB object (2)>": "ModelA.child_field" must be a "ModelA" instance.
>>> 
>>> model_b_6 = ModelB.objects.create(field_b="Value 6", child_field=model_a_2)
Traceback (most recent call last):
    raise ValueError(
ValueError: Cannot assign "<ModelA: ModelA object (2)>": "ModelB.child_field" must be a "ModelB" instance.
Вернуться на верх