How to add a relationship to a GeneratedField in Django

Context

I have a model:

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,
    )

I then have a view that unifies Paper and Website:

class Source(pg.View):
    sql = """
        SELECT ...
        FROM papers

        UNION ALL

        SELECT ...
        FROM websites
        ;
    """

    id = models.UUIDField(unique=True, primary_key=True)

    # ...

Question

I'd like to make it so from a Source model I can get the articles (e.g. source.articles.all()). How can I do that?

What have I tried?

I've tried to add this field to 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,
    )

But when creating the migration I get:

(models.E006) The field 'source' clashes with the field 'source_id' from model 'Article'.

I believe the problem is that you're running into a Django limitation:

ForeignKey fields auto-create a <field>_id attribute at the database level, so you cannot have both a model field named source_id and a ForeignKey source field, which causes the clash.

As @willeM_VanOnsem suggested, use an @property as a limited workaround.

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