1

I have simple result list in my admin panel. For example it is something like that:

id name description category

In my admin panel there is result list with classes "row1", "row2". I would like to add another class depending of obj value (obj.group_id which is not listed). I mean:

if obj.group_id == 2:
    add class "premium" to result list item  # whole row with this item

I would like to simply distinguish some rows in my django admin panel. I don't have any idea how can I achieve that. Any clues?

I am able to change css on one column. For example:

def show_url(self, obj):
    if obj.group.group_name == 'Premium':
        return format_html(
            '<span class="premium"><a style="color:blue" href="{}">{}</a></span>'.format(obj.url, obj.url)
        )
    return '<a style="color:blue" href="{}">{}</a>'.format(obj.url, obj.url)
show_url.allow_tags = True
show_url.short_description = "Url"

I would like to set different background to whole row...

1 Answer 1

2

Django doesn't make what you ask an easy task ...

First you need to create a new template_tags:
I called the file admin_override.py

# -*- coding: utf-8 -*-

from django.contrib.admin.templatetags.admin_list import (
    ResultList, items_for_result,
    result_headers, result_hidden_fields
)

from django.template import Library
register = Library()


def results(cl):
    if cl.formset:
        for res, form in zip(cl.result_list, cl.formset.forms):
            yield ResultList(form, items_for_result(cl, res, form))
    else:
        for res in cl.result_list:
            yield {
                'class': res.admin_css_class,
                'items': ResultList(None, items_for_result(cl, res, None))
            }


@register.inclusion_tag("admin/change_list_results_with_class.html")
def result_list_with_class(cl):
    """
    Displays the headers and data list together
    """
    headers = list(result_headers(cl))
    num_sorted_fields = 0
    for h in headers:
        if h['sortable'] and h['sorted']:
            num_sorted_fields += 1
    return {'cl': cl,
            'result_hidden_fields': list(result_hidden_fields(cl)),
            'result_headers': headers,
            'num_sorted_fields': num_sorted_fields,
            'results': list(results(cl))}

This new template_tag returns a list of dict instead of a list of ResultList, and change the rendering template to "admin/change_list_results_with_class.html".

Then you need to override change_list.html like in this answer

{% extends "admin/change_list.html" %}
{% load i18n admin_urls static admin_list admin_override%}

{% block result_list %}
    {% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %}
    {% result_list_with_class cl %}
    {% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %}
{% endblock %}

And finally you create admin/change_list_results_with_class.html

{% load i18n static %}
{% if result_hidden_fields %}
<div class="hiddenfields">{# DIV for HTML validation #}
{% for item in result_hidden_fields %}{{ item }}{% endfor %}
</div>
{% endif %}
{% if results %}
<div class="results">
<table id="result_list">
<thead>
<tr>
{% for header in result_headers %}
<th scope="col" {{ header.class_attrib }}>
   {% if header.sortable %}
     {% if header.sort_priority > 0 %}
       <div class="sortoptions">
         <a class="sortremove" href="{{ header.url_remove }}" title="{% trans "Remove from sorting" %}"></a>
         {% if num_sorted_fields > 1 %}<span class="sortpriority" title="{% blocktrans with priority_number=header.sort_priority %}Sorting priority: {{ priority_number }}{% endblocktrans %}">{{ header.sort_priority }}</span>{% endif %}
         <a href="{{ header.url_toggle }}" class="toggle {% if header.ascending %}ascending{% else %}descending{% endif %}" title="{% trans "Toggle sorting" %}"></a>
       </div>
     {% endif %}
   {% endif %}
   <div class="text">{% if header.sortable %}<a href="{{ header.url_primary }}">{{ header.text|capfirst }}</a>{% else %}<span>{{ header.text|capfirst }}</span>{% endif %}</div>
   <div class="clear"></div>
</th>{% endfor %}
</tr>
</thead>
<tbody>
{% for result in results %}
{% if result.form.non_field_errors %}
    <tr><td colspan="{{ result|length }}">{{ result.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %} {{ result.class }}">{% for item in result.items %}{{ item }}{% endfor %}</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}

You add a function in your model:

@property
def admin_css_class(self):
    return 'my_class'

This is tested and working.

Sign up to request clarification or add additional context in comments.

2 Comments

{{ item.admin_css_class }} doesn't work here. Item is called in next loop... I added function as you wrote but I don't know how can I use it in template...
You are right I did not follow pep20 "In the face of ambiguity, refuse the temptation to guess.". I'll edit my answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.