Suppose I have the following models, where Questions and Choices have a many-to-many relationship, and Choices and Voters have a many-to-many relationship. (To understand it better, consider a poll where each Question can have multiple Choices and each Choice can be associated to multiple Questions, and where each Choice stores a list of people who Voted for it, and Voters could have voted for multiple Choices.)
class Question(models.Model):
question_text = models.CharField(max_length=200)
choices = models.ManyToManyField('Choice')
class Choice(models.Model):
choice_text = models.CharField(max_length=200)
voters = models.ManyToManyField('Voter')
def __str__(self):
return self.choice_text
class Voter(models.Model):
name = models.CharField(max_length=500, default='FNU')
def __str__(self):
return self.name
Given a Question object ques1
, I want to be able to get a list of all Voters associated to the Choices for that question, i.e. I want a QuerySet of all Voters who voted for one or more of the Choices associated to the Question object ques1
.
Therefore if Choices c1
and c2
are associated to Question ques1
, and Voters v1
and v2
voted for Choice c1
and Voter v3
voted for Choice c2
, then running the query on Question ques1
, I would want a QuerySet containing [v1, v2, v3]
.
Is there any query for this?
The highly-inefficient workaround of course is to iterate through ques1.choices
, and update a running list of all voters with each iteration. I guess it could be made slightly more efficient by using select_related
, but not a spot on having a clean query.
We can do:
Voter.objects.filter(choice__in=ques1.choices.all()).distinct() # Used distinct() to get unique voters.
Read more about it in Django's official documentation.