"""
Returns the content for a specific cell.
- This method can be overridden by :meth:`render_FOO` methods on the table or
- by subclassing :class:`Column`.
-
+ This method can be overridden by :meth:`render_FOO` methods on the
+ table or by subclassing :class:`Column`.
"""
return value
``<input type="checkbox" .../>`` tag
:param header_attrs:
same as *attrs*, but applied **only** to the header checkbox
-
"""
+
def __init__(self, attrs=None, header_attrs=None, **extra):
params = {'sortable': False}
params.update(extra)
attrs.update(self.header_attrs)
return mark_safe('<input %s/>' % attrs.as_html())
- def render(self, value, bound_column, **kwargs):
+ def render(self, value, bound_column):
attrs = AttributeDict({
'type': 'checkbox',
'name': bound_column.name,
return mark_safe('<input %s/>' % attrs.as_html())
-
class LinkColumn(Column):
"""
A subclass of :class:`.Column` that renders the cell value as a hyperlink.
class PeopleTable(tables.Table):
name = tables.LinkColumn('people_detail', args=[A('pk')])
-
"""
+
def __init__(self, viewname, urlconf=None, args=None, kwargs=None,
current_app=None, attrs=None, **extra):
super(LinkColumn, self).__init__(**extra)
self.current_app = current_app
self.attrs = attrs or {}
- def render(self, value, record, bound_column, **kwargs):
+ def render(self, value, record, bound_column):
params = {} # args for reverse()
if self.viewname:
params['viewname'] = (self.viewname.resolve(record)
In order to use template tags or filters that require a
``RequestContext``, the table **must** be rendered via
:ref:`{% render_table %} <template-tags.render_table>`.
-
"""
+
def __init__(self, template_code=None, **extra):
super(TemplateColumn, self).__init__(**extra)
self.template_code = template_code
age = tables.Column()
``age`` is the name.
-
"""
+
def __init__(self, table, column, name):
self._table = table
self._column = column
:type table: :class:`.Table` object
:param table: the table containing the columns
-
"""
+
def __init__(self, table):
self.table = table
# ``self._columns`` attribute stores the bound columns (columns that
QUERYSET_ACCESSOR_SEPARATOR = '__'
+
class TableData(object):
"""
Exposes a consistent API for :term:`table data`. It currently supports a
This class is used by :class:.Table` to wrap any
input table data.
-
"""
+
def __init__(self, data, table):
from django.db.models.query import QuerySet
if isinstance(data, QuerySet):
:param order_by: the ordering to apply
:type order_by: an :class:`~.utils.OrderByTuple` object
-
"""
# translate order_by to something suitable for this data
order_by = self._translate_order_by(order_by)
for ... in ... default to using this. There's a bug in Django 1.3
with indexing into querysets, so this side-steps that problem (as well
as just being a better way to iterate).
-
"""
- return self.list.__iter__() if hasattr(self, 'list') else self.queryset.__iter__()
+ return (self.list.__iter__() if hasattr(self, 'list')
+ else self.queryset.__iter__())
def __getitem__(self, index):
"""Forwards indexing accesses to underlying data"""
return (self.list if hasattr(self, 'list') else self.queryset)[index]
-
class DeclarativeColumnsMetaclass(type):
Metaclass that converts Column attributes on the class to a dictionary
called ``base_columns``, taking into account parent class ``base_columns``
as well.
-
"""
- def __new__(cls, name, bases, attrs, parent_cols_from=None):
- """Ughhh document this :)
- """
+ def __new__(cls, name, bases, attrs, parent_cols_from=None):
+ """Ughhh document this :)"""
# extract declared columns
columns = [(name, attrs.pop(name)) for name, column in attrs.items()
if isinstance(column, Column)]
Extracts and exposes options for a :class:`.Table` from a ``class Meta``
when the table is defined.
"""
+
def __init__(self, options=None):
"""
:param order_by: sort the table based on these columns prior to display.
(default :attr:`.Table.Meta.order_by`)
+ :type sortable: ``bool``
+ :param sortable: Enable/disable sorting on this table
+
+ :type empty_text: ``string``
+ :param empty_text: Empty text to render when the table has no data.
+ (default :attr:`.Table.Meta.empty_text`)
+
The ``order_by`` argument is optional and allows the table's
``Meta.order_by`` option to be overridden. If the ``order_by is None``
the table's ``Meta.order_by`` will be used. If you want to disable a
default ordering, simply use an empty ``tuple``, ``string``, or ``list``,
e.g. ``Table(…, order_by='')``.
+
Example:
.. code-block:: python
order_by = request.GET.get('sort', ())
table = SimpleTable(data, order_by=order_by)
...
-
"""
__metaclass__ = DeclarativeColumnsMetaclass
TableDataClass = TableData
"""
Order the rows of the table based columns. ``value`` must be a sequence
of column names.
-
"""
# accept string
order_by = value.split(',') if isinstance(value, basestring) else value
@property
def sortable(self):
- return self._sortable if self._sortable is not None else self._meta.sortable
+ return (self._sortable if self._sortable is not None
+ else self._meta.sortable)
@sortable.setter
def sortable(self, value):
@property
def empty_text(self):
- return self._empty_text if self._empty_text is not None else self._meta.empty_text
+ return (self._empty_text if self._empty_text is not None
+ else self._meta.empty_text)
@empty_text.setter
def empty_text(self, value):
return self._columns
def as_html(self):
- """Render the table to a simple HTML table.
+ """
+ Render the table to a simple HTML table.
The rendered table won't include pagination or sorting, as those
features require a RequestContext. Use the ``render_table`` template
tag (requires ``{% load django_tables %}``) if you require this extra
functionality.
-
"""
template = get_template('django_tables/basic_table.html')
return template.render(Context({'table': self}))
@property
def attrs(self):
- """The attributes that should be applied to the ``<table>`` tag when
+ """
+ The attributes that should be applied to the ``<table>`` tag when
rendering HTML.
:rtype: :class:`~.utils.AttributeDict` object.
-
"""
return self._meta.attrs
<td>{{ cell }}</td>
{% endfor %}
</tr>
- {% empty %}
- {% if table.empty_text %}
- <tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
- {% endif %}
+ {% empty %}
+ {% if table.empty_text %}
+ <tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
+ {% endif %}
{% endfor %}
</tbody>
</table>
Ordering
========
-Changing the table ordering is easy. When creating a
-:class:`~django_tables.tables.Table` object include an `order_by` parameter
-with a tuple that describes the way the ordering should be applied.
+Changing the way a table is ordered is easy and can be controlled via the
+:attr:`.Table.Meta.order_by` option. The following examples all achieve the
+same thing:
.. code-block:: python
- table = CountryTable(countries, order_by=('name', '-population'))
- table = CountryTable(countries, order_by='name,-population') # equivalant
+ class SimpleTable(tables.Table):
+ name = tables.Column()
+
+ class Meta:
+ order_by = 'name'
-Alternatively, the :attr:`~django_tables.tables.Table.order_by` attribute can
-by modified.
+The following allows the ``Meta.order_by`` option to be overridden on a
+per-instance basis.
- table = CountryTable(countries)
- table.order_by = ('name', '-population')
- table.order_by = 'name,-population' # equivalant
+.. code-block:: python
+
+ class SimpleTable(tables.Table):
+ name = tables.Column()
+
+ table = SimpleTable(..., order_by='name')
+
+Finally the attribute method overrides both of the previous approaches.
+
+.. code-block:: python
+
+ class SimpleTable(tables.Table):
+ name = tables.Column()
+
+ table = SimpleTable(...)
+ table.order_by = 'name'
+
+----
+
+By default all table columns support sorting. This means that the headers for
+columns are rendered as links which allow that column to be toggled as the
+between ascending and descending ordering preference.
+
+Sorting can be disabled on a column, table, or table instance basis via the
+:attr:`.Table.Meta.sortable` option.
+
+To disable sorting by default for all columns:
+
+.. code-block:: python
+
+ class SimpleTable(tables.Table):
+ name = tables.Column()
+
+ class Meta:
+ sortable = False
+
+To disable sorting for a specific table instance:
+
+.. code-block:: python
+
+ class SimpleTable(tables.Table):
+ name = tables.Column()
+
+ table = SimpleTable(..., sortable=False)
+ # or
+ table.sortable = False
.. _pagination:
>>> table.as_html()
'<table class="mytable">...'
-Inspired by Django's ORM, the ``class Meta:`` allows you to define extra
-characteristics of a table. See :class:`Table.Meta` for details.
-
.. _table.render_foo:
... id = tables.Column()
... age = tables.Column()
...
- ... def render_row_number(self, **kwargs):
+ ... def render_row_number(self):
... value = getattr(self, '_counter', 0)
... self._counter = value + 1
... return 'Row %d' % value
...
- ... def render_id(self, value, **kwargs):
+ ... def render_id(self, value):
... return '<%s>' % value
...
>>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
{% for row in table.rows %}
<tr>
{% for cell in row %}
- <td>{{ cell }}</td>
+ <td>{{ cell }}</td>
{% endfor %}
</tr>
+ {% empty %}
+ {% if table.empty_text %}
+ <tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
+ {% endif %}
{% endfor %}
</tbody>
</table>
>>> import django_tables as tables
>>>
>>> class AngryColumn(tables.Column):
- ... def render(self, *args, **kwargs):
- ... raw = super(AngryColumn, self).render(*args, **kwargs)
- ... return raw.upper()
+ ... def render(self, value):
+ ... return value.upper()
...
>>> class Example(tables.Table):
... normal = tables.Column()
>>> table.as_html()
u'<table><thead><tr><th>Normal</th><th>Angry</th></tr></thead><tbody><tr><td>May I have some food?</td><td>GIVE ME THE FOOD NOW!</td></tr><tr><td>Hello!</td><td>WHAT ARE YOU LOOKING AT?</td></tr></tbody></table>\n'
+See :ref:`table.render_foo` for a list of arguments that can be accepted.
+
Which, when displayed in a browser, would look something like this:
+-----------------------+--------------------------+
>>> from django.utils.safestring import mark_safe
>>>
>>> class ImageColumn(tables.Column):
- ... def render(self, **kwargs):
- ... raw = super(AngryColumn, self).render(**kwargs)
- ... return mark_safe('<img src="/media/img/%s.jpg" />' % raw)
+ ... def render(self, value):
+ ... return mark_safe('<img src="/media/img/%s.jpg" />' % value)
...
-----------------------------
.. autoclass:: django_tables.columns.BoundColumns
- :members: all, items, names, sortable, visible, __iter__,
+ :members: all, items, sortable, visible, __iter__,
__contains__, __len__, __getitem__
--------------------------
.. autoclass:: django_tables.rows.BoundRows
- :members: all, page, __iter__, __len__, count
+ :members: __iter__, __len__, count
:class:`BoundRow` Objects