Hi! Was just seeing this exchange for the first time.
At work, we have a similar case:
- For a specific ModelAdmin, we want to add a conditional CSS class to each row in the result list.
- If we override
change_list_results.html, we need to do it for ALL model admins, there is no `admin/app-name/` pattern here.
- This sends us off in a bad direction of having to create our own derivative of the
result_list that we use in our admin/app-name/change_list.html simply in order to use a different template in the inclusion_tag
See: Overriding the Django admin change_list_results.html only for some models - Stack Overflow
Here are some options to reframe the discussion…
Option 1: New options for template overriding?
(UPDATED: @KenWhitesell pointed out a factual error in the original option, so this is replaced with a different take)
We have the option to replace the template for our LawnMower model by adding a template admin/machines/lawnmower/change_list_results.html.
So we can override it, especially to swap out this part:
But here’s the problem (noted by colleague)
It was trickier than expected to figure out that change_list_results.html is rendered by Django’s result_list inclusion tag, which creates its own isolated context. So you can’t just add stuff to response.context_data - it won’t make it to the template. Had to attach the CSS map to the cl (ChangeList) object itself since that’s the one thing that actually gets passed through.
This option needs someone’s input: What would be a nice, clean way to include a custom property on <tr>? Would additional configuration on ModelAdmin be desirable? Do we continue to inject things into the cl (change list) object?
Option 2: Fetching row properties per model instance?
Since there isn’t a real notion of a row, nor its properties, we would need to add that. I think we don’t want to mix properties with the queryset and the objects we’re iterating on.
I think what we’d end up with is something like:
@admin.register(models.LawnMower)
class LawnMowerAdmin(admin.ModelAdmin):
def get_row_properties(self, obj: models.LawnMower):
properties = super().get_row_properties(self, obj)
if not obj.for_sale:
# This is a very TR-oriented suggestion.
# We might wanna design for CSS grids etc.
# Having a dictionary is perhaps the most flexible approach.
properties["tr_attributes"]["css"].append("disabled")
return properties
Then we need to adjust change_list_results.html to also read these properties.
I think we could come up with more row-related properties useful for other purposes:
- Color-coding
- Collapsible
- Hidden
- Sticky?
- Translation stuff?
- CSS grid flows?
Option 3: CSS selector workaround 
As a final addition, consider that you can actually do a lot with CSS selectors that would otherwise be much harder to do in Python and Django templates:
tr:has(td.field-some_field img.active) td {
background-color: lime;
}
So any row that contains a <img class="active"> would have a specific background color defined on <td>s. You’d need to fill this in with your own field-specific properties, but this can go a long way for adding simple styling to row elements.