John
John

Reputation: 21927

Change row colour in Django Admin List

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.

Upvotes: 16

Views: 13176

Answers (4)

Elf Sternberg
Elf Sternberg

Reputation: 16361

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.

Upvotes: 27

philippe
philippe

Reputation: 31

class FilmAdmin(admin.ModelAdmin):
 def get_film_status(self, obj):
        if obj.status() != 'active':
            return mark_safe("<span class='row_gray'>%s</span>" % obj.status())

 class Media:
        js = ("js/my_admin.js", )

and in my_admin.js :

window.onload = function() {
    var x=document.getElementsByClassName("row_gray");
    var i;
    for (i = 0; i < x.length; i++) {
        var ligne=x[i].parentNode;
        while (ligne.tagName !== "TR") {ligne=ligne.parentNode;}
        ligne.style.backgroundColor = "lightgray";
    }
}

Upvotes: 3

Elf Sternberg
Elf Sternberg

Reputation: 16361

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.

Upvotes: 10

s29
s29

Reputation: 2057

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

Upvotes: 10

Related Questions