Simple Search With Django ORM (Posted on March 30th, 2013)

Many websites find it useful to have a search box on their site to enable their users to find content easier. I just wanted to share a simple way that I was able to do it using the Django ORM.

The first step will be to get the user's query then split it into an array for each word.

query = " Django search " #Search query entered by user
query = query.split() #Remove excess spaces and split the query into array items

The next step is to build our query using the ORM. To do this we'll use Django's Q object which allows us to perform OR queries in our database. We'll also make all our queries case insensitive so that our results aren't thrown off by capitalization issues. One idea may to achieve this would be to do something like:

from django.db.models import Q
compiled = None
for word in query:
    if compiled == None:
        compiled = Q(content__icontains=word)
        compiled = compiled | Q(content__icontains=word)
entries = Entry.objects.filter(compiled)

However, Python has a built in function that will greatly clean up our code and give us the same affect. The function we're looking for is called reduce. Reduce will take all the objects in an iterable, run them through a function, and return the result.

If you check out the reduce documentation you'll see that the first argument is a function. Luckily Django provides us with a function to create OR and AND queries. So we can pass Q.__or__ as our function to the reduce call.

Next we need to pass an iterable to the reduce function. If you're familiar with list comprehensions then you should see where this is headed. If not check the code below.

from django.db.models import Q
compiled = reduce(Q.__or__, [Q(content__icontains=word) for word in query])
entries = Entry.objects.filter(compiled)

The previous two sets of code will yield the same results so it's really your call as to how you want to view your code.

Overall two lines of code and an import statement isn't too bad for a simple search. As always if you have any feedback or questions feel free to drop them in the comments below or contact me privately on my contact page. Thanks for reading!

Tags: Django