开发者

Conditional nested filters in Django

开发者 https://www.devze.com 2023-03-08 19:28 出处:网络
I have a django model, lets say: class Person(models.Model): first_name = models.CharField(max_length=25)

I have a django model, lets say:

class Person(models.Model):
   first_name = models.CharField(max_length=25)
   last_name  = models.CharField(max_length=25)

And, exists a search form, where I can search rows whether by first_name, by last_name or by both. I have noted that I can link filters in a django queryset, e.g:

def search(request):
   list = Person.objects.filter(first_name= val1).filter(last_name=val2)

But what if one of the values val1, val2 is null? Should I do something like:

def searh(request):
   if val1 != null and val2 == null:
      list = Person.objects.filter(first_name= val1)
   if val2 == null and val2 != null:
       list = Person.objects.filter(last_name= val2)
   if val2 != null and val2 != null:
       list = Person.objects.filter(first_name= val1).filter(last开发者_Go百科_name=val2)

Is there any direct way to do this?

thanks in advance


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.


(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.

0

精彩评论

暂无评论...
验证码 换一张
取 消