akajb
akajb

Reputation: 255

Django ManyToMany reverse query with specific key

I have two tables. The first, is a basic user table. And the second is a table called Section.

def User(models.Model):
    ...
    is_teacher = models.BooleanField(default=False)
    ...

def Section(models.Model):
    ...
    teachers = models.ManyToManyField(User, related_name="teachers")
    students = models.ManyToManyField(User, related_name="students")
    is_active = models.BooleanField(default=True)
    ...

I would like to get all the student users (identified in the User table with is_teacher=False) which I know can be done easily with User.objects.filter(is_teacher=False).

I would like to also get the active section(s) for each user.

But, at the moment, I can't even seem to get the set of sections for the users.

I've tried:

students = User.objects.filter(is_teacher=False)
for s in students:
    print s.section_set.all()

But I'm getting an error that User object has no section_set. I'm guessing because the section has two many to many relationships with the User table (teachers and students), I probably have to specify the relationship more clearly (to follow the students one not the teachers one). But I'm not sure how to do this.

Upvotes: 1

Views: 1797

Answers (3)

Ihor Pomaranskyy
Ihor Pomaranskyy

Reputation: 5611

When defining related_name value, keep in mind that this a name for backwards relation (in your case — from User to Section). So, to keep your code clear and easy to understand, I'd recommend you to change the names like this:

def Section(models.Model):
    ...
    teachers = models.ManyToManyField(User, related_name="sections_where_teacher")
    students = models.ManyToManyField(User, related_name="sections_where_student")
    is_active = models.BooleanField(default=True)
    ...

Then using the relations looks like this:

print s.sections_where_student.all()

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599600

You've defined related_name explicitly on your ManyToMany fields, so that is the accessor you should use:

print s.students.all()

Not that the actual names you've used don't make much sense; the reverse relationship is not "students", it's "sections as a student".

Upvotes: 0

Wagh
Wagh

Reputation: 4306

try this:

sec = Section.object.filter(students = students, is_active=True)

you will get the section objects for the students who is active.

Upvotes: 0

Related Questions