Skip to content

Adds support for header_value for export header #970

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
28 changes: 28 additions & 0 deletions django_tables2/columns/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,26 @@ def header(self):
"""
return self.verbose_name

@property
def header_value(self):
"""
The value used for the column heading in exports.

By default this returns `~.Column.header`.

:returns: `unicode` or `None`
Copy link
Owner

Choose a reason for hiding this comment

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

Isn't unicode a python 2 construct?

Suggested change
:returns: `unicode` or `None`
:returns: `str` or `None`


.. note::

This property typically is not accessed directly when a table is
rendered. Instead, `.BoundColumn.header_value` is accessed which
in turn accesses this property. This allows the header to fallback
to the column name (it is only available on a `.BoundColumn` object
hence accessing that first) when this property doesn't return something
useful.
"""
return self.header

def footer(self, bound_column, table):
"""Return the content of the footer, if specified."""
footer_kwargs = {"column": self, "bound_column": bound_column, "table": table}
Expand Down Expand Up @@ -556,6 +576,14 @@ def header(self):
# fall back to automatic best guess
return self.verbose_name

@property
def header_value(self):
"""The contents of the header for this column in an export."""
column_header_value = self.column.header_value
if column_header_value:
return column_header_value
return self.header
Comment on lines +582 to +585
Copy link
Owner

Choose a reason for hiding this comment

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

I think we can safely write this as:

Suggested change
column_header_value = self.column.header_value
if column_header_value:
return column_header_value
return self.header
return column_header_value or self.header


@property
def footer(self):
"""The contents of the footer cell for this column."""
Expand Down
2 changes: 1 addition & 1 deletion django_tables2/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ def value_name(self, value):
if not (column.column.exclude_from_export or column.name in exclude_columns)
]

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

for row in self.rows:
yield [
Expand Down
22 changes: 19 additions & 3 deletions docs/pages/custom-data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ Please refer to `.Table.as_values` for an example.
Subclassing `.Column`
---------------------

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

>>> import django_tables2 as tables
>>>
Expand Down Expand Up @@ -186,3 +186,19 @@ For complicated columns, you may want to return HTML from the
... def render(self, value):
... return format_html('<img src="/media/img/{}.jpg" />', value)
...

When subclassing a column, the header in the html table can be customized by
overriding :meth:`~Column.header`. The header value for exports can be independently
customized using :meth:`~Column.render_value`.
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
customized using :meth:`~Column.render_value`.
customized using :meth:`~Column.render_value`.



>>> from django.utils.html import format_html
>>>
>>> class PartyColumn(tables.Column):
... @property
... def header(self):
... return format_html('<div><marquee>PaRtY!</marquee></div>')
...
... @property
... def header_value(self):
... return "party"
4 changes: 4 additions & 0 deletions docs/pages/export.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ By default, it just calls the `render()` method on that column.
If your custom column produces HTML, you should override this method and return
the actual value.

For column headers, similarly sometimes :ref:Column.header`-may include html which
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
For column headers, similarly sometimes :ref:Column.header`-may include html which
For column headers, similarly sometimes :ref:Column.header`-may include HTML which

would be inappropriate to include in an export. For this case, the `:ref:Column.header_value`
can be used to override the column header only in exports.


Including and excluding columns
-------------------------------
Expand Down
15 changes: 15 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,21 @@ def value_country(self, value):

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

def test_as_value_header_value(self):
class CustomColumn(tables.Column):
@property
def header_value(self):
return "CUSTOM"

class Table(tables.Table):
name = tables.Column()
country = CustomColumn()

expected = [["Name", "CUSTOM"]] + [[r["name"], r["country"]] for r in self.AS_VALUES_DATA]
table = Table(self.AS_VALUES_DATA)

self.assertEqual(list(table.as_values()), expected)

def test_as_values_accessor_relation(self):
programmer = Occupation.objects.create(name="Programmer")
henk = Person.objects.create(
Expand Down