django-tables2 specify different properties for different rows
Asked Answered
S

4

8

I would like to create a table with django-tables2 such that different rows have different properties.

By default I get either

<tr class="odd">

or

<tr class="even">

How can I specify my own class for some of the rows?

Similarly, if I have a CheckBoxColumn and I specify some data for this column, it goes into the value:

<input type="checkbox" name="col" value="123"/>

This is great for figuring out which checkbox was checked. However, how can I set some checkboxes as checked when the table is created?

My scenario: the user picks some rows from a large table. For example, the table has

  • orange 1
  • orange 2
  • apple 5
  • orange 3
  • apple 4
  • cucumber 7
  • aaple 1

The user picks aaple 5 and cucumber 7.

Then I would like to display all apples and all cucumbers, since the user picked at least one apple and at least one cucumber. This allows the user to see other relevant entries:

  • apple 5
  • apple 4
  • cucumber 7

However, I would like to highlight the entries actually picked by the user by using css and/or by displaying a checked checkbox:

  • apple 5
  • apple 4
  • cucumber 7
Spaceless answered 1/3, 2012 at 23:10 Comment(1)
I guess this contains a solution for this issue Conditional statements in Django_tables2 class definitionEstop
S
9

Well, let me post my own solution.

I have copied the standard template table.html and edited it. I only changed one line:

<tbody>
    {% for row in table.page.object_list|default:table.rows %} {# support pagination #}
    {% block table.tbody.row %}
    <tr class="{{ row.tr_class }}">  <!-- CLASS FOR EACH ROW -->

instead of

    <tr class="{% cycle "odd" "even" %}">

This way you can set a different class for each row in the table. It remains to add an invisible column to your table class:

class MyTable(tables.Table):
  tr_class=tables.Column(visible=False)
  ... # other columns

After that, whenever you are creating a table, you can set any CSS classes for any particular rows. Remember to use the modified template:

{% render_table div_table "modifiedtable.html" %}  

Of course, you can also change the original table.html.

Can anybody suggest a more graceful solution?

Overall, I have a feeling that django_tables2 is still missing many important features, so I have to reinvent the wheel every time I am trying to do something nontrivial.

Define tr_class

To use this, you must use custom rendering. For example:

class MyTable(tables.Table):
 tr_class=tables.Column(visible=False, empty_values=())
 def render_tr_class(self, value):
   if value.chosen == True:
     return 'highlight'

And the tr would be given the class highlight.

Spaceless answered 13/3, 2012 at 18:42 Comment(1)
For anyone else coming along, you need to add empty_values=() to the column definition i.e.: tr_class=tables.Column(visible=False, empty_values=())Ronel
M
5

I have a very easy workaround for this

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

    def render_source(self, value):
        if value == 'some_value':
            return mark_safe("<span class='highlight_this_row'>%s</span>" % (escape(value)))
        else:
            return value

Then instead of creating a complete custom HTML page for custom rendering, you could just use jQuery to actually highlight the row.

$('.highlight_this_row').parent().parent().addClass('highlight');

If you don't have a class "highlight" defined, you can define it as:

<style>
    .highlight{
        background-color: black
    }
</style>
Mroz answered 24/9, 2015 at 6:56 Comment(2)
This my friend is the right answer. Now the possibilities are endless. Thanks!Obedient
simple and elegant solutionRhigolene
A
4

There's another way (also not very beautiful), but here you don't have to define a fake column.

First, you extend django_tables2.rows.BoundRows:

class ColoredBoundRows(BoundRows):
    def __iter__(self):
        for record in self.data:
            row = BoundRow(record, table=self.table)
            row.style = 'some_class'
            yield row

    def __getitem__(self, key):
        container = ColoredBoundRows if isinstance(key, slice) else BoundRow
        return container(self.data[key], table=self.table)

Then make your Table use it:

class YourTable(Table):
    def __init__(self, *args, **kwargs):
        super(YourTable, self).__init__(*args, **kwargs)
        self.rows = ColoredBoundRows(data=self.data, table=self)

Then define a new template (note that you only have to overwrite one block):

{% extends "django_tables2/table.html" %}

{% block table.tbody.row %}
<tr class="{% cycle "odd" "even" %} {{ row.style }}">
  {% for column, cell in row.items %}
    <td {{ column.attrs.td.as_html }}>{{ cell }}</td>
  {% endfor %}
</tr>
{% endblock table.tbody.row %}
Ademption answered 14/3, 2013 at 18:51 Comment(0)
J
0

I actually couldn't get the accepted answer to work for this, perhaps the latest version of django_tables2 is different. Here is my solution, which doesn't require modifying the tables.html template and is based on the documentation.

First define row_attrs as part of the class Meta

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

    class Meta:
        row_attrs = {'class': my_custom_row_attrs}

You can then define a function outside the scope of MyTable to work out your row attributes depending on the values in the individual row record

def my_custom_row_attrs(**kwargs):
    '''My function to generate custom row attributes
    '''

    record = kwargs.get('record', None)
    tr_class = ''

    if record:
        # Only do comparison if pat_date is present
        if record.my_column.value == True:
            tr_class = 'highlight'

    return tr_class

I would rather keep all this functionality within the class, but this seemed the best way to do it to avoid modifying anything else.

Jobye answered 2/10, 2018 at 7:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.