How to apply multiple filters in a Django query without knowing if some filters are null or not

Viewed 152

Let's say we have the following filters:

filter1 = request.GET.get("blabla")
filter2 = request.GET.get("blabla")
filter3 = request.GET.get("blabla")
filter4 = request.GET.get("blabla")
filter5 = request.GET.get("blabla")
filter6 = request.GET.get("blabla")

Let's say we have the following query:

user_projects = Project.objects.filter(element1=filter1, element2=filter2, element3=filter3, element4=filter4, element5=filter5, element6=filter6).distinct().values("id", "name", "customer_id", "dev_status", "manager_id", "total_billable")

Some of the filters might be of type None (depends on the request)

I would like to create a dynamic query that based on whether the filter exists or not, executes the query only with the non-null filters.

Let's say for example filters 1, 2, and 3 have values, but filters 4, 5, and 6 are empty/null/None.

Expected query:

user_projects = Project.objects.filter(element1=filter1, element2=filter2, element3=filter3).distinct().values("id", "name", "customer_id", "dev_status", "manager_id", "total_billable")

What I've tried:

if filter1 is None or filter1.strip() == "":
        filter1 = ""
    elif is_valid_queryparam(filter1):
        user_projects = Project.objects.filter(element1=filter1).distinct().values("id", "name", "customer_id", "dev_status", "manager_id", "total_billable")

And it works, but only for one filter, if I want that for 6 or N filters, it's extremely inefficient to execute multiple queries.

Is it possible to achieve the desired result with a simple query?

1 Answers

You can make a utility method, like:

filter_qs_if_not_None(qs, **kwargs):
    return qs.filter(
        **{key: value for key, value in kwargs.items() if value is not None and value.strip()}
    )

Then we can filter with:

user_projects = filter_qs_if_not_None(
    Project.objects.all(),
    element1=filter1,
    element2=filter2,
    element3=filter3,
    element4=filter4,
    element5=filter5,
    element6=filter6
)
Related