Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #499 - add default "class" HTML attribute to footers #501

Merged
merged 18 commits into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
## 1.15.0 (2017-11-23)
- Added `as=varname` keyword argument to the `{% querystring %}` template tag,
fixes [#481](https://github.com/jieter/django-tables2/issues/481)
- Updated the tutorial to reflect current state of Django a bit better.
- Updated the tutorial to reflect current state of Django a bit better
- Used `OrderedDict` rather than `dict` as the parent for `utils.AttributeDict` to make the rendered html more consistant accross python versions.
- Allow reading column `attrs` from a column's attribute, allowing easier reuse of custom column attributes (fixes [#241](https://github.com/jieter/django-tables2/issues/241))
- `value` and `record` are optionally passed to the column attrs callables for data rows. [#503](https://github.com/jieter/django-tables2/pull/503), fixes [#500](https://github.com/jieter/django-tables2/issues/500)
- Added `tf` dictionary to `Column.attrs` with default values for the footer, so footers now have `class` attribute by default

## 1.14.2 (2017-10-30)
- Added a `row_counter` variable to the template context in `TemplateColumn` (fixes [#448](https://github.com/jieter/django-tables2/issues/488))
Expand Down
12 changes: 8 additions & 4 deletions django_tables2/columns/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Column(object):
the data iterator returned from as_values().
footer (str, callable): Defines the footer of this column. If a callable
is passed, it can take optional keyword argumetns `column`,
`bound_colun` and `table`.
`bound_column` and `table`.
order_by (str, tuple or `.Accessor`): Allows one or more accessors to be
used for ordering rather than *accessor*.
orderable (bool): If `False`, this column will not be allowed to
Expand Down Expand Up @@ -298,9 +298,10 @@ def attrs(self):
'''
Proxy to `.Column.attrs` but injects some values of our own.

A ``th`` and ``td`` are guaranteed to be defined (irrespective of
what's actually defined in the column attrs. This makes writing
templates easier.
A ``th``, ``td`` and ``tf`` are guaranteed to be defined (irrespective
of what's actually defined in the column attrs. This makes writing
templates easier. ``tf`` is not actually a HTML tag, but this key name
will be used for attributes for column's footer, if the column has one.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the tf key here. Maybe footer is better, although that is a html tag, but not relevant to a table...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have given it a lot of thought and chosen the best abbreviation, in my opinion, having in mind the tags and the actual non-existence of "the footer tag". I also understand why you disagree because it looks like I've been there too.

Please let me know what key name will you decide and I'll gladly update the code.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's go for tf for now, thanks for explaining

'''

# prepare kwargs for computed_values()
Expand All @@ -327,14 +328,17 @@ def attrs(self):
# override with attrs defined specifically for th and td respectively.
attrs['th'] = computed_values(attrs.get('th', cell_attrs), kwargs=kwargs)
attrs['td'] = computed_values(attrs.get('td', cell_attrs), kwargs=kwargs)
attrs['tf'] = computed_values(attrs.get('tf', cell_attrs), kwargs=kwargs)

# wrap in AttributeDict
attrs['th'] = AttributeDict(attrs['th'])
attrs['td'] = AttributeDict(attrs['td'])
attrs['tf'] = AttributeDict(attrs['tf'])

# Override/add classes
attrs['th']['class'] = self.get_th_class(attrs['th'])
attrs['td']['class'] = self.get_td_class(attrs['td'])
attrs['tf']['class'] = self.get_td_class(attrs['tf'])

return attrs

Expand Down
2 changes: 1 addition & 1 deletion django_tables2/templates/django_tables2/semantic.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
{% if table.has_footer %}
<tr>
{% for column in table.columns %}
<td>{{ column.footer }}</td>
<td {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
{% endfor %}
</tr>
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion django_tables2/templates/django_tables2/table.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<tfoot>
<tr>
{% for column in table.columns %}
<td>{{ column.footer }}</td>
<td {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
{% endfor %}
</tr>
</tfoot>
Expand Down
7 changes: 5 additions & 2 deletions docs/pages/column-attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ Depending on the column, different elements are supported, however ``th``,


For ``th`` and ``td``, the column name will be added as a class name. This makes
selecting the row for styling easier.
Have a look at each column's API reference to find which elements are supported.
selecting the row for styling easier. Have a look at each column's API
reference to find which elements are supported.

If you need to add some extra attributes to column's tags rendered in the
footer, use key name ``tf``, as described in section on :ref:`css`.

Callables passed in this dict will be called, with optional kwargs ``table``,
``bound_column`` ``record`` and ``value``, with the return value added. For example::
Expand Down
38 changes: 38 additions & 0 deletions docs/pages/custom-rendering.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,44 @@ a hook that allows arbitrary attributes to be added to the ``<table>`` tag.
>>> # renders to something like this:
'<table class="mytable">...'

Also every column gets a class attribute, which by default is the same as the
column's label. Also, by default, odd rows' class is ``odd`` and even rows'
class is ``even``. So rows of the ``SimpleTable()`` from previous example
in django-tables2 default configuration will look like:

.. sourcecode:: html

<tr class="odd">
<td class="id">...</td>
<td class="age">...</td>
</tr>
<tr class="even">
<td class="id">...</td>
<td class="age">...</td>
</tr>

You can also specify ``attrs`` attribute when creating a column. ``attrs``
is a dictionary which contains attributes which by default get rendered
on various tags involved with rendering a column. You can read more about
them in :ref:`column-attributes`. django-tables2 supports 3 different
dictionaries, this way you can give different attributes
to column tags in table header (``th``), rows (``td``) or footer (``tf``)

.. sourcecode:: python

>>> import django_tables2 as tables
>>>
>>> class SimpleTable(tables.Table):
... id = tables.Column(attrs={'td': {'class': 'my-class'}})
... age = tables.Column(attrs={'tf': {'bgcolor': 'red'}})
...
>>> table = SimpleTable()
>>> # renders to something like this:
'<tbody><tr><td class="my-class">...</td></tr>'
>>> # and the footer will look like this:
'<tfoot><tr> ... <td class="age" bgcolor="red"></tr></tfoot>''


.. _custom-template:

Custom Template
Expand Down
2 changes: 1 addition & 1 deletion requirements/common.pip
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ pytz>0
pytest
pytest-django
pytest-cov
tablib==0.11.4
tablib==0.11.4
5 changes: 3 additions & 2 deletions tests/test_faq.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import django_tables2 as tables

from .utils import build_request
from .utils import build_request, parse

TEST_DATA = [
{'name': 'Belgium', 'population': 11200000},
Expand Down Expand Up @@ -42,4 +42,5 @@ class CountryTable(tables.Table):
table = CountryTable(TEST_DATA)
html = table.as_html(build_request())

assert '<td>Total: 77740000</td>' in html
columns = parse(html).findall(".//tfoot/tr")[-1].findall("td")
assert columns[1].text == "Total: 77740000"
57 changes: 48 additions & 9 deletions tests/test_footer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# coding: utf-8
import django_tables2 as tables

from .utils import build_request
from .utils import build_request, parse

MEMORY_DATA = [
{'name': 'Queensland', 'country': 'Australia', 'population': 4750500},
Expand Down Expand Up @@ -31,11 +31,11 @@ class Table(tables.Table):

table = Table(MEMORY_DATA)
assert table.has_footer() is True

html = table.as_html(build_request('/'))

assert '<td>Total:</td>' in html
assert '<td>18833000</td>' in html
columns = parse(html).findall(".//tfoot/tr")[-1].findall("td")
assert columns[1].text == "Total:"
assert columns[2].text == "18833000"


def test_footer_disable_on_table():
Expand All @@ -52,17 +52,56 @@ class Table(tables.Table):


def test_footer_column_method():
class SummingColumn(tables.Column):
def render_footer(self, bound_column, table):
return sum(
bound_column.accessor.resolve(row) for row in table.data)

class TestTable(tables.Table):
name = tables.Column()
country = tables.Column(footer='Total:')
population = SummingColumn()

table = TestTable(MEMORY_DATA)
html = table.as_html(build_request('/'))

columns = parse(html).findall(".//tfoot/tr")[-1].findall("td")
assert columns[1].text == "Total:"
assert columns[2].text == "18833000"


def test_footer_has_class():
class SummingColumn(tables.Column):
def render_footer(self, bound_column, table):
return sum(bound_column.accessor.resolve(row) for row in table.data)
return sum(
bound_column.accessor.resolve(row) for row in table.data)

class Table(tables.Table):
class TestTable(tables.Table):
name = tables.Column()
country = tables.Column(footer='Total:')
population = SummingColumn()

table = Table(MEMORY_DATA)
table = TestTable(MEMORY_DATA)
html = table.as_html(build_request('/'))

columns = parse(html).findall(".//tfoot/tr")[-1].findall("td")
assert "class" in columns[1].attrib


def test_footer_custom_attriubtes():
class SummingColumn(tables.Column):
def render_footer(self, bound_column, table):
return sum(
bound_column.accessor.resolve(row) for row in table.data)

class TestTable(tables.Table):
name = tables.Column()
country = tables.Column(footer='Total:', attrs={'tf': {'align': 'right'}})
population = SummingColumn()

table = TestTable(MEMORY_DATA)
table.columns['country'].attrs['tf'] = {'align': 'right'}
html = table.as_html(build_request('/'))
assert '<td>Total:</td>' in html
assert '<td>18833000</td>' in html

columns = parse(html).findall(".//tfoot/tr")[-1].findall("td")
assert "align" in columns[1].attrib