[Django]-Conditional nested filters in Django

6👍

✅

def search(request, val1, val2):
    persons = Person.objects.all()
    if val1:
        persons = persons.filter(first_name=val1)
    if val2:
        persons = persons.filter(last_name=val2)
    return persons

This works (isn’t inefficient) because Querysets are lazy.

5👍

(Disclaimer: tested in Python 2.7, Django 1.6, although it should work in general)

I’ve been recently introduced to the following construct that directly applies to OP’s issue:

def search(request, val1, val2):
    filter_args={}
    if val1:
        filter_args["first_name"]=val1
    if val2:
        filter_args["last_name"]=val2

    persons = Person.objects.filter(**filter_args)

    return persons

Basically, this will construct a filter with more than one criterion, even if you don’t know a-priori whether both val1 and val2 will be available. It’ll construct the most specific filter using conjunction (and) it can, without needing extra logic evaluation to overcome the fact that .filter(...).filter(...) always evaluates the criterions using disjunction (or). If later you want to add age to your conjunction, for instance, just add the following two lines (and val3 to the function argument list):

    if val3:
        filter_args["age"]=val3

I’m using this methodology in a project I’m working on to great success, and thought this information might be useful to newer Django users with this same question.

Leave a comment