Как добавить связь к сгенерированному полю в Django
Контекст
У меня есть модель:
class Article(models.Model):
id = models.UUIDField(default=uuid4, editable=False, unique=True, primary_key=True)
paper_id: UUID | None
paper = models.ForeignKey["Paper"](
"Paper",
on_delete=models.CASCADE,
related_name="articles",
null=True,
blank=True,
)
website_id: UUID | None
website = models.ForeignKey["Website"](
"Website",
on_delete=models.CASCADE,
related_name="articles",
null=True,
blank=True,
)
Тогда у меня есть представление, которое объединяет Paper
и Website
:
class Source(pg.View):
sql = """
SELECT ...
FROM papers
UNION ALL
SELECT ...
FROM websites
;
"""
id = models.UUIDField(unique=True, primary_key=True)
# ...
Вопрос
Я бы хотел сделать так, чтобы из модели Source
я мог получить модель articles
(например, source.articles.all()
).
Как я могу это сделать?
Что я пробовал?
Я пытался добавить это поле в Article
:
source_id = models.GeneratedField(
expression=Coalesce(F("paper_id"), F("website_id")),
output_field=models.UUIDField(),
db_persist=False,
)
source = models.ForeignKey["Source"](
"Source",
on_delete=models.DO_NOTHING,
related_name="articles",
db_column="source_id",
to_field="id",
null=True,
editable=False,
)
Но при создании миграции я получаю:
(models.E006) Поле "источник" противоречит полю "source_id" из модели "Article".
Я полагаю, проблема в том, что вы сталкиваетесь с ограничением Django:
Поля ForeignKey автоматически создают атрибут <field>_id
на уровне базы данных, поэтому у вас не может быть одновременно поля model с именем source_id
и ForeignKey source
поле, которое вызывает столкновение.
Как предложил @willeM_VanOnsem, используйте @property
в качестве ограниченного обходного пути.