Conditionally Filter Within Django Queryset

Solution 1:

I don't believe there is a built-in way to do this in Django specifically, but you can make use of the dictionary unpack operator ** and a dictionary comprehension to achieve the desired result.

For example:

some_name = 'Bob'
field_value_pairs = [('gender', 'boy'), ('name', some_name)]
filter_options = {k:v for k,v in field_value_pairs if v}
qs = MyModel.objects.filter(**filter_options)

So if some_name is None, then the 'name' field will be excluded from filter_options and therefore not be included in the filter query.


Update:

You can also use the Q object to build a query that can be passed to a single call of the filter method. This allows for more flexibility and allows for more complex filtering similar to the SQL WHERE clause.

For example:

from django.db.models import Q

some_name = 'Bob'
query = Q(gender='boy')
if some_name:
    query = query & Q(name=some_name)
qs = MyModel.objects.filter(query)

Or if you want a more compact view for simple cases like this:

query = Q(gender='boy') & (Q(name=some_name) if some_name else Q())

or (closer to your desired look):

qs = MyModel.objects.filter(Q(gender='boy') & (Q(name=some_name) if some_name else Q()))

Note that using separate filter calls isn't really bad since only one database query will be made (assuming you don't try to reference the objects in the query set before the last filter call). You can check this by looking at the database queries Django is making. But as a matter of style, I can see the preference for only calling filter once.