1. adminbrowse: Fancier changelist columns in Django’s admin site

    I just released a new reusable Django app called django-adminbrowse on GitHub. This was factored out of a Django project I’ve been working on for a while.

    Ever wish it was easier to get around in the Django admin? Maybe you’ve deployed the admin site as a management tool for some less technical users? This project lets you easily spiff up changelist pages to include better text and markup. I’ve been using it in production for a while and it’s been a welcome improvement.

    In the screenshot (click to zoom), you’ll notice:

    • URL fields become clickable links.
    • Foreign key fields link to the change form for the corresponding object.
    • Related objects get a link to their changelist page, filtered appropriately.

    There are a few more features, but the most powerful is that the code is very easily extensible. If you ever wanted to include a custom markup in your changelist columns, this makes it really easy.

    See the README or use Python’s help() for starters. More advanced documentation is in progress.

    Enjoy!

  2. django-batchadmin: Batch actions in the admin change list

    I’m releasing a new project tonight: django-batchadmin. It looks like this:

    Django with batchadmin enabled

    Plenty of people have done this before with recipes or patches. But this is a project, and it’s distributed as a Django app, not with copy & paste or a diff. Also, since it’s being released post-1.0, it uses the latest and greatest in newforms-admin features.

    The app is very minimal but customizable. There’s only one action included in the app: delete. Refer to the Getting Started page to add your own actions.

    All functionality is added with a ModelAdmin subclass called BatchModelAdmin. This simply puts a checkbox in each row, specifies a change list template that wraps a form around the list, and makes the view accept POST requests, which it dispatches to the action code.

    Stay tuned for some custom actions.

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