Reputation: 103
So I have a form where user can post Parent
details also form for Kid for a different model.
what i need is to allow users to access list of Parent
objects by filtering their related objects Kid
let's say a filter to list Parents objects that has children named X
older than Z
live in Y
city AND has no children named X
who is younger than Z
live in Y
city .
models.py :
class Parent(models.Model):
title = models.CharField(max_length=250)
class Kid(models.Model):
cities = (
('city1', city1),
('city2', city2)
)
family = models.ForeignKey(Parent)
title = models.CharField(max_length=250)
age = models.CharField(max_length=250)
city = models.CharField(choices=cities)
any idea how to do it or where/what to look for the answer?
Upvotes: 0
Views: 43
Reputation: 630
Related manager seems like a feasible option.
Django offers a powerful and intuitive way to “follow” relationships in lookups, taking care of the
SQL JOINs
for you automatically, behind the scenes. To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.It works backwards, too. To refer to a “reverse” relationship, just use the lowercase name of the model.
parents = Parent.objects.filter(kid__name=X,kid__age__gte=Y,kid__city=Z)
PS: I have not tested this code. The intention is to give a suggestion on approach.
Edit 1: Addressing the exclude exception as pointed in the comments. Link to Django documentation. Refer to the note in this section
Exclude behavior is different than filter. Exclude in related manager doesn't use a combination of conditions instead excludes both eg. Parent.objects.exclude(kid__name=X,kid__city=Z)
will exclude kids with name X
and kids from city Z
instead of kids with name X
who are from city Z
Django suggested approach is:
Parent.objects.exclude(kid__in=Kid.objects.filter(name=X,city=Z))
Upvotes: 0
Reputation: 15370
You can do it in reversed logic. Firstly you need to change age
to IntegerField
otherwise you wouldn't be able to compare it's values
class Kid(models.Model):
family = models.ForeignKey(Parent)
title = models.CharField(max_length=250)
age = models.IntegerField()
city = models.CharField(choices=cities)
Then you can filter all kids that comply with your filter and get ids of parents to filter on later
filter_ids = Kid.objects.filter(name=X, age__gte=Z, city=Y).values_list('parents_id', flat=True).distinct()
exclude_ids = Kid.objects.filter(name=X, age__lt=Z, city=Y).values_list('parents_id', flat=True).distinct()
parents = Parent.objects.filter(id__in=filter_ids).exclude(id__in=exclude_ids)
Answering comment Same logic you firstly fillter all parents with such kids, then you exclude parents that have other kids.
filter_ids = Kid.objects.filter(my_pattern).values_list('parents_id', flat=True).distinct()
exclude_ids = Kid.objects.exclude(my_pattern).values_list('parents_id', flat=True).distinct()
parents = Parent.objects.filter(id__in=filter_ids).exclude(id__in=exclude_ids)
Upvotes: 1