user2950593
user2950593

Reputation: 9617

Django querying many to many relations

I have 3 models: group, word, phrase

As you can see word belongs to group and there is a many to many relation between phrases and words:

class Group(models.Model):
    name = models.TextField()


class Word(models.Model):  
    group = models.ForeignKey(Group, on_delete=models.SET_NULL, null=True,
    related_name = "words")

class Phrase(models.Model):
    words = models.ManyToManyField(Word, null=True,related_name = "phrases")
    name = models.TextField()

And right now I need to find all phraseswith name ="xxx" that have at least one word from group with group id = '177'

How do I do this?

Upvotes: 1

Views: 62

Answers (2)

Deniz Kaplan
Deniz Kaplan

Reputation: 1609

Phrase.objects.filter(name="xxx", words__group__id=177)

You can filter all phrases with name "xxx" and one of words' group_id equals 177.

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476537

You can do this with a filter that both filters on the name field, and the words__group_id=177:

Phrase.objects.filter(
    name='xxx',
    words__group_id=177
).distinct()

We here thus use a JOIN on the words and the phrase_words table, and then filter such that the group_id of the Word is 177.

The .distinct() can be important, since if mutliple words are in the group with id 177, then that Phrase would be repeated multiple times.

This works in case id is the primary key of the Group. If you defined another column named id, and that column is not the primary key (which is quite uncommon), we can use:

Phrase.objects.filter(
    name='xxx',
    words__group__id=177
).distinct()

Mind that here we use two consecutive underscores (__) instead of one (_) to look "through" the foreign key. In this case, this will result in an extra JOIN at the database level, and therfore can be a bit less efficient.

Upvotes: 1

Related Questions