Django: Question regarding queries over a junction table/intermediary model

Question:

My question concerns the many-to-many section of the django models docs:

It is mentioned there that by using an intermediary model it is possible to query on the intermediary model’s attributes like so:

Person.objects.filter(
    group__name='The Beatles',
    membership__date_joined__gt=date(1961,1,1))

However for the other many-to-many model (Group) a similar query results in a FieldError:

# which groups have a person name containing 'Paul'?
Group.objects.filter(person__name__contains="Paul")

Yet queries that reference the junction table explicity do work:

Person.objects.filter(membership__group__name__contains="The Beatles")
Group.objects.filter(membership__person__name__contains="Paul")

Shouldn’t Group therefore have access to Person via the junction model?

Models:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)
Asked By: upgrd

||

Answers:

"The model that defines the ManyToManyField uses the attribute name of
that field itself
, whereas the “reverse” model uses the lowercased
model name of the original model, plus ‘_set’ (just like reverse
one-to-many relationships)." (docs: Many-to-many relationships)

So instead of

Group.objects.filter(person__name__contains="Paul")

the correct query is

Group.objects.filter(members__name__contains="Paul")

since the related model is accessible via the name of the field attribute (not the model).

Answered By: upgrd
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.