views:

39

answers:

3

I want to highlight rows (set the backgorund colour) in the Django Admin page (change_list.html) based on a field in the model called status. What is the best way to do this?

I have 3 statuses. Open, Active, Closed. I'd like rows with open to be green, active to be orange and closed to be red.

I've found documentation about changing the templates so but not sure how to check the status to colour the row.

+1  A: 

As it turns out, customizing the change_list_results.html and the associated generator is quite a bear. I'd like to propose a completely different solution: Override change_list.html for your application, and use Javascript to do the effect you want.

I had exactly the same problem you have. For a film library, I needed to know if the filmmaker's registration was "active" or something else. Here's the entirety of my override:

{% extends "admin/change_list.html" %}

{% block extrahead %}
{{ block.super }}
<script type="text/javascript">
(function($) {
    $(document).ready(function() {
        $('#result_list tr td:nth-child(7)').each(function() {
            if ($(this).text() != 'active') {
                $(this).css('background-color', 'orange');
            }
        });
    });
})(django.jQuery);
</script>
{% endblock %}

This file is ${TEMPLATE_DIR}/admin/films/film/change_list.html. Django's result list is id'd "result_list," all I do here is decorate column 7 with a different background style if the contents of the column are not to my liking.

The admin provides jQuery already, so no additional changes to your application or admin are necessary to make this work.

Elf Sternberg
Oh, and if you want to just change the whole row (Christmasy!) you can do that by targeting all the children of the parent: $('td', $(this).parent('tr')) instead of $(this).
Elf Sternberg
+1  A: 

I was wrong, there's another alternative using just the Django admin app.

In the admin.py for your app, you can define a renderer for the contents of a table cell. Here's the variant for my film library:

class FilmAdmin(admin.ModelAdmin):

   def film_status(self, obj):
        if obj.status() != 'active':
            return '<div style="width:100%%; height:100%%; background-color:orange;">%s</div>' % obj.status()
        return obj.status()
    film_status.allow_tags = True

    list_display = ('id', 'title', 'film_status')

admin.site.register(Film, FilmAdmin)

Here, I've created a field name, 'film_status', that does not exist in the Film model, and defined it as a method of FilmAdmin. It gets passed the item for every row. I've had to tell the renderer to allow_tags, which tells the admin app not to "safe" the HTML content.

This won't fill the whole cell, though, as the cell itself has some padding. Only the part of the cell your app is allowed to fill (as defined by the admin's stylesheet) will be filled. But it's good enough for my purposes.

There you go. Two completely different, but useful, techniques for decorating the content of a cell in a Django admin list.

Elf Sternberg
A: 

Check out django-liststyle, exactly what you're after.

s29