Writing a search view with Django

While working on the latest incarnation of my website, I decided that it was time that I figured out how to enable searching of my website. Ever since I converted my site from Wordpress, searching my site hasn’t been possible, unless using a search engine and limiting it only to my domain. This was less than agreeable with me since it seems like something that could be written in Django, especially since the admin interface already has a search that works.

After scouring the web looking for some code to help me along the path, I eventually came across this post on Petro Verkhogliad’s blog. Using Petro’s code as a starting point, I was able to work out something of my own, which is a bit simpler, and feels more… Django-ish. Below is the code that I’m using for my current implementation of search. It returns two variables to the template results and query.

results is a list object with references to all the blog postings that match your query. query is a simple reference to your search terms, which is useful for pre-populating search forms, or inserting the terms into a header or other text area.

from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404
from django.db.models import Q
from wolfsreign.apps.blog.models import Post

def search(request):
    query = request.GET.get("s", "")
    q = Q()
    for term in query.split( ):
        results = Post.objects.filter(Q(status="Published"), Q(title__icontains=term) | Q(body__icontains=term))
    results = list(results)
        q |= Q(title__icontains=term) | Q(body__icontains=term)
    results = Post.objects.filter(Q(status="Published"), q)
    return render_to_response("search/results.html", {"results": results,"query": query})

This view sends the context to the results template, which might looks like this:

<h1>Search results for {{ query }}</h1>
<ul>
{% for result in results %}
      <li><a href="{{ results.get_absolute_url }}">{{ results.title }}</a></li>
{% endfor %}
</ul>

Hopefully this helps some of you, like it’s helped me.

As Sago points out, my original code was not using all of the search terms that were being provided. It was only searching based on the last word in the search. I have updated the code to reflect his suggested changes. If you have been using my older code, you might find it beneficial to update your code.

About this Entry

You're currently reading "Writing a search view with Django" posted by Steven

Published:
1.22.07 / 12PM
Category:
This site , Django

Nine Comments

Jump to comment form
  1. David Zuch 3.6.07 / 10am Edit | Delete

    Two suggestions:

    1. Style your pre tags.
    2. Submit this to djangosnippets.org
  2. Steven Ametjan 3.6.07 / 9pm Edit | Delete

    What if I don’t want to style my pre tags?

  3. Petro 3.6.07 / 11pm Edit | Delete

    Nicely done. I have been meaning to go over that code but have no time. :)

  4. David Zuch 3.7.07 / 4pm Edit | Delete

    Well then you’re just being stubborn.

  5. Steven Ametjan 3.7.07 / 5pm Edit | Delete

    I supposed you’re also going to tell me that I need to style my ol‘s and my ul‘s in my comments too.

  6. David Zuch 3.7.07 / 5pm Edit | Delete

    That was next on my list…

  7. JamiecURLe 3.16.07 / 1pm Edit | Delete

    I’ve been looking for examples of this all day !

    The mercury tide solution (http://www.mercurytide.com/whitepapers/django-full-text-search/ ) whilst nice, I did feel like there was too much ‘jiggery pokery’ needed to be done.

    On the subject of your <pre /> tags, Firefox 2 on OSX renders the text almost too small to read. Luckily for me I have the eyes of hawk.

    Thanks & Enjoy,

    Jamie.

  8. Sago 4.5.07 / 7pm Edit | Delete

    Unfortunately, your code doesn’t work.

    You throw away the results of every search term but the last:

    for term in query.split( ):
        results = Post.objects.filter ...
    

    Instead compile a Q from each term

    q = Q()
    for term in query.split():
        q |= Q(title__icontains=term) | Q(body__icontains=term))
    

    Then run it once:

    results = Post.objects.filter(Q(status="Published"), q)
    
  9. Steven Ametjan 4.5.07 / 11pm Edit | Delete

    Thanks, Sago. I noticed that my searches were a little off from what I was expecting, but I couldn’t figure out why.

    I’ll update my code.


About Me

I am an Application Developer for Fox Interactive Media. I am currently in the Stations group, working on the MyFox family of sites (MyFox LA). On top of working for FIM, I also design and develop websites for myself and on as a freelance contractor.

I have been working in the industry professionally for the past four years, and have worked with great companies, and even greater people. Some of the companies that I've had the pleasure to work for include Schematic, Iventa, 101communications (now 1105media), and MySpace.

If you want to know more about me, continue reading.