1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
from django.template import Context, Template
from django.template.loader import get_template
from django.utils.html import strip_tags
from .base import Column, library
@library.register
class TemplateColumn(Column):
"""
A subclass of `.Column` that renders some template code to use as
the cell value.
Arguments:
template_code (str): template code to render
template_name (str): name of the template to render
extra_context (dict): optional extra template context
A `~django.template.Template` object is created from the
*template_code* or *template_name* and rendered with a context containing:
- *record* -- data record for the current row
- *value* -- value from `record` that corresponds to the current column
- *default* -- appropriate default value to use as fallback.
- *row_counter* -- The number of the row this cell is being rendered in.
- any context variables passed using the `extra_context` argument to `TemplateColumn`.
Example:
.. code-block:: python
class ExampleTable(tables.Table):
foo = tables.TemplateColumn("{{ record.bar }}")
# contents of `myapp/bar_column.html` is `{{ label }}: {{ value }}`
bar = tables.TemplateColumn(template_name="myapp/name2_column.html",
extra_context={"label": "Label"})
Both columns will have the same output.
"""
empty_values = ()
def __init__(self, template_code=None, template_name=None, extra_context=None, **extra):
super().__init__(**extra)
self.template_code = template_code
self.template_name = template_name
self.extra_context = extra_context or {}
if not self.template_code and not self.template_name:
raise ValueError("A template must be provided")
def render(self, record, table, value, bound_column, **kwargs):
# If the table is being rendered using `render_table`, it hackily
# attaches the context to the table as a gift to `TemplateColumn`.
context = getattr(table, "context", Context())
additional_context = {
"default": bound_column.default,
"column": bound_column,
"record": record,
"value": value,
"row_counter": kwargs["bound_row"].row_counter,
}
additional_context.update(self.extra_context)
with context.update(additional_context):
if self.template_code:
return Template(self.template_code).render(context)
else:
return get_template(self.template_name).render(context.flatten())
def value(self, **kwargs):
"""
The value returned from a call to `value()` on a `TemplateColumn` is
the rendered template with `django.utils.html.strip_tags` applied.
Leading and trailing whitespace is stripped.
"""
html = super().value(**kwargs)
return strip_tags(html).strip() if isinstance(html, str) else html
|