Django / Python — Dynamically Create Queries from a String and the OR operator


Dynamically create queries from strings in django.

My problem: I wanted to make a searchable, sorted list of an arbitrary amount of fields to check against.

Normally, we’d use a  Q object to get to the | “or” operator. Our search might look like the following:

Person.objects.filter( Q(first_name__icontains='Yuji') | Q(last_name__icontains='Tomita')

What if I don’t want to hard code the field names? I want to use dynamic field names so I can use a basic factory on multiple models very easily.

With much needed prodding in the right direction by mattmcc, I figured it out.

The key was how to use keyword arguments as strings.

is equal to:
Person.objects.filter( **{'first_name__icontains':'Yuji'})

With this knowledge, and operator.or_, I could do a Q and | lookup via strings.

query_string = "Some Name" # the search string
argument_list = []
fields = ('search_field1','search_field2','search_field3')
for query in query_string.split(' '): # split search words
for field in fields:
argument_list.append( Q(**{field+'__icontains': query} )
query = MyModel.objects.filter(  reduce(operator.or_, argument_list)  ) # join the arguments in the list with the or operator

15 thoughts on “Django / Python — Dynamically Create Queries from a String and the OR operator

  1. Really useful post. I didn’t realize that it’s possible to pass a dictionary to .filter() instead of using the “shorthand” (which until reading this post was the only syntax I’d seen). It’s great to discover that it’s possible to reference field names dynamically while looping through lists!

  2. I’m really glad it helped! This was a useful discovery since I wasn’t aware of the **{ } syntax.

    I am absolutely positive this will pop up again in my Python travels 😀

  3. What if I want to reference a field NOT in a query? Like
    thismonth = now.strftime(“%b”).lower() # this returns the abbreviated month (e.g. “nov”)
    ff = something.objects.get(id__exact == 1)
    print ff.thismonth #<<<— Here is where I would like to have "thismonth" be variable as there is one field for each month in the table.

    Any ideas?

      1. I have a table, say “months”, with fields: jan, feb, mar, apr, etc. I want to print out the value of the current month, which I can do by:

        ff = months.objects.get(id__exact = 1) #purely for example here!)
        print ff.nov

        But I want it to work for the current month, without me having to have a pile of if statements, something like this:

        thismonth = now.strftime(“%b”).lower() #this month = “nov” right now
        ff = months.objects.get(id__exact = 1) #purely for example here!)
        print ff.thismonth

        This last line doesn’t work, obviously, but I want it to have the same effect as “print ff.nov”. I want to use the variable “thismonth” to tell python/django which database field to look at.

        Not sure how to be more clear!

    1. Ah, well that doesn’t really have anything to do with querysets 😛

      I’d use an instance property or method:

      class MyModel(...):
          def thismonth(self):
               return getattr(self, now().strftime("%b").lower(), None)
      model = MyModel.objects.get(id=1)
      print model.thismonth
  4. Thanks! I realize this has nothing to do with querysets, except that when I was searching for the solution to this, I kept finding answers to how to use variables within the querysets instead of what I was looking for. So to ME it’s related 🙂 Cheers.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s