Search code examples
djangodjango-tables2

How do I customize a column based on its value?


Using django-tables2 is very easy from your model to get a table. In my case I need one of my table columns to be formated based on its value.

In my current html table it would look like below:

{% if record.status|stringformat:"s" == "New" %}
    <td class="bg-success></td>

If the value is New the cell background should be green.

From what I could find there are maybe 3 ways to do something like this:

Updated solutions:

1.Create a class and a css rule with the appropriate background color and add it to the column:

class MyTable(tables.Table):    
    status = tables.Column(attrs={"class": lambda record: record.status})

.New {
background-color: green
}

This way it works, although I think that record.status could work, without the lambda.

2.You can specify how to render a column:

class MyTable(tables.Table):    
    status = tables.Column()

    def render_status(self, value):
        if value.name == "New":
            change class accordingly

The change class accordingly part eludes me.

Also you can create a custom column:

class StatusColumn(tables.Column):
    def render(self, value):
        if value == "New":
            return format_html('<span class="text-success">{}</span>', value)

I made this work using a span tag to pass a bootstrap class to format the cell.

3.Use a TemplateColumn and pass html:

class MyTable(tables.Table):  
    status = tables.TemplateColumn("""
    {% if record.status|stringformat:"s" == "New" %}
        <td class="bg-success"></th>
    {% else %}
        <td class="bg-danger"></th>
    {% endif %}
    """)

This way a new column is created formated correctly.

I am still searching how to do this and I would appreciate any help.


Solution

  • Depending on what your exact needs are, there are different solutions.

    1. Changing the appearance of the cell (<td></td>)

    If you want to add attributes to the <td> tag, you must use something django-tables2 calls column attributes.

    It supports fixed values, but also allows a callable to use some value of the record being rendered. Say for instance, you have a record containing a field color and you want to use that color as the background color for the cell.

    class Table(tables.Table):
        person = tables.Column(attrs={
            'td': {
                'class': 'person-column',
                'style': lambda record: 'background-color: {}'.format(record.color)
            }
        })
    

    Or more specifically for your example:

    class MyTable(tables.Table):    
        status = tables.Column(attrs={'td': {'class': lambda value: 'bg-success' if value == 'New' else 'bg-danger' }})
    

    or without lambda:

    def status_attr(record):
        return 'bg-success' if value == 'New' else 'bg-danger'
    
    class MyTable(tables.Table):    
        status = tables.Column(attrs={'td': {'class': status_attr}})
    

    2. changing the contents of the cell

    By contents I mean everything within the <td></td> tag. The API of django-tables2 allows for various ways to change the contents of a cell, which is called custom data in the documentation.

    Your solutions 2 and 3 already show the ways to do that, however, you can not change the cell attributes in those ways. You might be able to achieve output looking like this <td><td class="bg-success">...</td></td>, which might look like what you want, but are not valid HTML.