1. Rendering search results in Django

    This weekend I wrote a Django tag & filter module for rendering search results. The primary feature is truncating a body of text to show the search terms in context, just like Google shows you an excerpt. A decent text indexer will normally provide this, but most of my projects aren’t big enough to justify setting one up, so I make do with normal database queries.

    Examples and documentation are on the snippet page, but here’s how I actually use it in my latest project. I have some flatpages storing documentation and other help for the web site, and a search form just for these pages. The following code can practically be dropped into any Django project using flatpages.

    The view looks like this:

    from django.contrib.flatpages.models import FlatPage
    from django.db.models import Q
    
    def help_search(request):
        query_string = request.GET.get('q', "")
        search_terms = query_string.split()
        results = FlatPage.objects.filter(url__startswith="/help/")
    
        if search_terms:
            query = Q()
            for term in search_terms:
                query &= Q(content__icontains=term) | Q(title__icontains=term)
            results = results.filter(query)
    
        return render_to_response("flatpages/search.html",
            {'query': query_string, 'terms': search_terms, 'results': results}
        )
    

    And the relevant portion of flatpages/search.html looks like this:

    {% load search %}
    
    <h1>Search Results</h1>
    <h2>
        {% with results|length as result_count %}
        {{ result_count|default:"No" }} page{{ result_count|pluralize }} found
        {% if terms %}for &ldquo;{{ query }}&rdquo;{% endif %}
        {% endwith %}
    </h2>
    <ul id="results">
        {% for page in results %}
        <li>
            {% searchexcerpt terms 6 as content %} {# set `content` object #}
                {{ page.content|striptags }}
            {% endsearchexcerpt %}
            {% highlight terms as title %} {# set `title` object #}
                {{ page.title }}
            {% endhighlight %}
            <h3>
                <a href="{{ page.get_absolute_url }}">{{ title.highlighted }}</a>
                {% if terms %}{% with content.hits|add:title.hits as hits %}
                <span class="count">{{ hits }} hit{{ hits|pluralize }}</span>
                {% endwith %}{% endif %}
            </h3>
            <p class="context">{{ content.excerpt|highlight:terms }}</p>
        </li>
        {% endfor %}
    </ul>
    

    Finally, here are some screenshots of the results:

    Search screenshot 1Search screenshot 2Search screenshot 3