Skip to content

Commit b2edd12

Browse files
committed
Adds support for header_value for export header
1 parent f39cfd7 commit b2edd12

File tree

5 files changed

+67
-4
lines changed

5 files changed

+67
-4
lines changed

django_tables2/columns/base.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,26 @@ def header(self):
338338
"""
339339
return self.verbose_name
340340

341+
@property
342+
def header_value(self):
343+
"""
344+
The value used for the column heading in exports.
345+
346+
By default this returns `~.Column.header`.
347+
348+
:returns: `unicode` or `None`
349+
350+
.. note::
351+
352+
This property typically is not accessed directly when a table is
353+
rendered. Instead, `.BoundColumn.header_value` is accessed which
354+
in turn accesses this property. This allows the header to fallback
355+
to the column name (it is only available on a `.BoundColumn` object
356+
hence accessing that first) when this property doesn't return something
357+
useful.
358+
"""
359+
return self.header
360+
341361
def footer(self, bound_column, table):
342362
"""Return the content of the footer, if specified."""
343363
footer_kwargs = {"column": self, "bound_column": bound_column, "table": table}
@@ -556,6 +576,14 @@ def header(self):
556576
# fall back to automatic best guess
557577
return self.verbose_name
558578

579+
@property
580+
def header_value(self):
581+
"""The contents of the header for this column in an export."""
582+
column_header_value = self.column.header_value
583+
if column_header_value:
584+
return column_header_value
585+
return self.header
586+
559587
@property
560588
def footer(self):
561589
"""The contents of the footer cell for this column."""

django_tables2/tables.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ def value_name(self, value):
493493
if not (column.column.exclude_from_export or column.name in exclude_columns)
494494
]
495495

496-
yield [force_str(column.header, strings_only=True) for column in columns]
496+
yield [force_str(column.header_value, strings_only=True) for column in columns]
497497

498498
for row in self.rows:
499499
yield [

docs/pages/custom-data.rst

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ Please refer to `.Table.as_values` for an example.
151151
Subclassing `.Column`
152152
---------------------
153153

154-
Defining a column subclass allows functionality to be reused across tables.
155-
Columns have a `render` method that behaves the same as :ref:`table.render_foo`
156-
methods on tables::
154+
Defining a column subclass allows further customization and functionality to
155+
be reused across tables. Columns have a `render` method that behaves the same
156+
as :ref:`table.render_foo` methods on tables::
157157

158158
>>> import django_tables2 as tables
159159
>>>
@@ -186,3 +186,19 @@ For complicated columns, you may want to return HTML from the
186186
... def render(self, value):
187187
... return format_html('<img src="/media/img/{}.jpg" />', value)
188188
...
189+
190+
When subclassing a column, the header in the html table can be customized by
191+
overriding :meth:`~Column.header`. The header value for exports can be independently
192+
customized using :meth:`~Column.render_value`.
193+
194+
195+
>>> from django.utils.html import format_html
196+
>>>
197+
>>> class PartyColumn(tables.Column):
198+
... @property
199+
... def header(self):
200+
... return format_html('<div><marquee>PaRtY!</marquee></div>')
201+
...
202+
... @property
203+
... def header_value(self):
204+
... return "party"

docs/pages/export.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ By default, it just calls the `render()` method on that column.
8080
If your custom column produces HTML, you should override this method and return
8181
the actual value.
8282

83+
For column headers, similarly sometimes :ref:Column.header`-may include html which
84+
would be inappropriate to include in an export. For this case, the `:ref:Column.header_value`
85+
can be used to override the column header only in exports.
86+
8387

8488
Including and excluding columns
8589
-------------------------------

tests/test_core.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,21 @@ def value_country(self, value):
661661

662662
self.assertEqual(list(Table(self.AS_VALUES_DATA).as_values()), expected)
663663

664+
def test_as_value_header_value(self):
665+
class CustomColumn(tables.Column):
666+
@property
667+
def header_value(self):
668+
return "CUSTOM"
669+
670+
class Table(tables.Table):
671+
name = tables.Column()
672+
country = CustomColumn()
673+
674+
expected = [["Name", "CUSTOM"]] + [[r["name"], r["country"]] for r in self.AS_VALUES_DATA]
675+
table = Table(self.AS_VALUES_DATA)
676+
677+
self.assertEqual(list(table.as_values()), expected)
678+
664679
def test_as_values_accessor_relation(self):
665680
programmer = Occupation.objects.create(name="Programmer")
666681
henk = Person.objects.create(

0 commit comments

Comments
 (0)