Reputation: 495
I have a form which allows a user to select users by multiple age ranges: 18-24, 25-34, 35-44 etc. Currently if a user selects the first two fields in the multiple selection list, the query will return users 18 - 34. If a user selects 18 - 24 year olds, and 35-44 year olds, it will include all ages from 18 - 44, when it should not include users aged 25-34.
How would you approach including multiple range filters on a query without knowing the number of ranges you need to filter by prior to the users form selections?
If you knew the number of age ranges the user was going to filter by I know you could chain range queries using Q.
This is my current query:
query = User.objects.filter(
gender__in=genders,
created__in=dates,
data_source__in=sources,
dob__range=[dob_from, dob_to]
)
Thanks in advance.
Upvotes: 1
Views: 1410
Reputation: 309069
As you say in your question, you can use Q()
objects and combine them together. It's not a problem that you don't know how many Q()
objects there will be. Generate a list of the Q() objects, then reduce the list to a single Q()
.
from operator import or_
# import for Python 3, not required in Python 2
from functools import reduce
ranges = [(18,24), (35, 44)] # hardcoded as an example, you can dynamically generate this
qs = [Q(dob_range=[dob_from_, dob_to]) for (dob_from_, dob_to) in ranges]
# combine the qs
dob_q = reduce(or_, qs, Q())
query = User.objects.filter(
dob_q,
gender__in=genders,
created__in=dates,
data_source__in=sources,
)
If you are unfamiliar with reduce
and or_
, you can get the same result by looping through the list:
qs = [Q(dob_range=[dob_from_, dob_to]) for (dob_from_, dob_to) in ranges]
dob_q = Q()
for q in qs:
dob_q = dob_q | q
Upvotes: 7