Reputation: 44798
I have a DB schema like so:
class Family(models.Model):
pass
class Child(models.Model):
family = models.ForeignKey(Family)
name = models.TextField()
age = models.IntegerField()
gender = models.CharField(max_length=1)
I want a query that returns all children in families that have boys under 5.
How do I express this? Closest I got is:
# WRONG: this is no good, it will only return boys under 5, but I want all
# children in families with boys under 5.
Child.objects.filter(gender='M', age__lt=5)
# WRONG: this is no good, it is closer but will also return children in
# families with a 6yo boy and a 3yo girl.
Child.objects.filter(family__child__gender='M', family__child__age__lt=5)
Upvotes: 0
Views: 93
Reputation: 44798
As @knbk pointed out in a comment, I was actually wrong when I wrote the question. I assumed a default behavior that wasn't there. The best answer, then, is the one I gave:
Child.objects.filter(family__child__gender='M', family__child__age__lt=5)
If you wanted to retrieve all children in families with a male child and one (possibly a different one) who is under 5, you'd have to do this:
Child.objects.filter(family__child__gender='M').filter(family__child__age__lt=5)
And here's the documentation link @knbk provided which details the feature: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
If he answers, I'll move the points to him.
Upvotes: 0
Reputation: 6735
You can try an __in
-query like this:
boys_under_5 = Child.objects.filter(gender='M', age__lg=5)
Child.objects.filter(family__child__in=boys_unter_5)
As to why your original query doesn't work, I suggest reading the generared SQL:
print Child.objects.filter(family__child__gender='M', family__child__age__lt=5).query
Upvotes: 1
Reputation: 3981
Get the id
s of the Family
s that have boys under 5, then filter Child
on those id
s. The following query only hits the database once:
Child.objects.filter(
family__in=Family.objects.filter(child__gender='M', child_age__lt=5).values('id')
)
Upvotes: 1
Reputation: 114
You stated that you wanted all boys in families with boys under 5 It's a big ambiguous but I'm going to assume that you want families that contain at least one boy that is under 5
This would work:
families = Family.objects.filter(child__gender='M', child__age__lt=5).prefetch_related('child')
Then you could iterate over the family objects to retrieve their respective children
Upvotes: 1