pythondjangomodel

django %(class)s does not get correctly replaced when used in m2m relationship to self in abstract model


Django docs advise to set related_name and related_query_name using class/app name placeholders %(class)s and %(app_label)s.

I am finding that in an abstract model with a many-to-many field to itself, these labels are not replaced correctly. Is this because they are unnecessary in a "self" many-to-many relationship?

class GeographicalArea(models.Model):
    successors = models.ManyToManyField(
        "self",
        symmetrical=False,
        blank=True,
        related_name="%(class)s_predecessors",
        related_query_name="%(app_label)s_%(class)s_predecessor",
        help_text="Successors of area if changed.",
    )

    class Meta:
        abstract = True

class Country(GeographicalArea):
    name = models.CharField(
        blank=False,
        unique=True,
        db_index=True,
    )

...generates a migration script where related_name='%(class)s_predecessors' and related_query_name='%(app_label)s_%(class)s_predecessor' instead of related_name='country_predecessors' and related_query_name='myapp_country_predecessor' as I expected.


Solution

  • The migrations don't display the final names, but it will work anyway.

    Run the migrations, related_name and related_query_name will be as expected:

    from my_app.models import Country
    Country._meta.get_field("successors").remote_field.related_query_name
    >>> 'my_app_country_predecessors'