From: Bradley Ayers Date: Fri, 15 Apr 2011 10:22:18 +0000 (+1000) Subject: * Added ability to specify an empty_row value for tables X-Git-Tag: v0.4.0.beta6~1^2~2 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=3beb7f2b7036e59d6630d96ae34f42820aeaf345;p=django-tables2.git * Added ability to specify an empty_row value for tables --- diff --git a/django_tables/columns.py b/django_tables/columns.py index cf46a63..1af2a81 100644 --- a/django_tables/columns.py +++ b/django_tables/columns.py @@ -100,9 +100,8 @@ class Column(object): """ 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 @@ -137,8 +136,8 @@ class CheckBoxColumn(Column): ```` 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) @@ -154,7 +153,7 @@ class CheckBoxColumn(Column): attrs.update(self.header_attrs) return mark_safe('' % attrs.as_html()) - def render(self, value, bound_column, **kwargs): + def render(self, value, bound_column): attrs = AttributeDict({ 'type': 'checkbox', 'name': bound_column.name, @@ -164,7 +163,6 @@ class CheckBoxColumn(Column): return mark_safe('' % attrs.as_html()) - class LinkColumn(Column): """ A subclass of :class:`.Column` that renders the cell value as a hyperlink. @@ -210,8 +208,8 @@ class LinkColumn(Column): 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) @@ -222,7 +220,7 @@ class LinkColumn(Column): 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) @@ -281,8 +279,8 @@ class TemplateColumn(Column): In order to use template tags or filters that require a ``RequestContext``, the table **must** be rendered via :ref:`{% render_table %} `. - """ + def __init__(self, template_code=None, **extra): super(TemplateColumn, self).__init__(**extra) self.template_code = template_code @@ -321,8 +319,8 @@ class BoundColumn(object): age = tables.Column() ``age`` is the name. - """ + def __init__(self, table, column, name): self._table = table self._column = column @@ -426,8 +424,8 @@ class BoundColumns(object): :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 diff --git a/django_tables/tables.py b/django_tables/tables.py index bc92e9e..f3ba21e 100644 --- a/django_tables/tables.py +++ b/django_tables/tables.py @@ -13,6 +13,7 @@ from .columns import BoundColumns, Column QUERYSET_ACCESSOR_SEPARATOR = '__' + class TableData(object): """ Exposes a consistent API for :term:`table data`. It currently supports a @@ -20,8 +21,8 @@ class TableData(object): 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): @@ -46,7 +47,6 @@ class TableData(object): :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) @@ -76,14 +76,13 @@ class TableData(object): 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): @@ -91,12 +90,10 @@ 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)] @@ -131,6 +128,7 @@ class TableOptions(object): Extracts and exposes options for a :class:`.Table` from a ``class Meta`` when the table is defined. """ + def __init__(self, options=None): """ @@ -159,12 +157,20 @@ class Table(StrAndUnicode): :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 @@ -176,7 +182,6 @@ class Table(StrAndUnicode): order_by = request.GET.get('sort', ()) table = SimpleTable(data, order_by=order_by) ... - """ __metaclass__ = DeclarativeColumnsMetaclass TableDataClass = TableData @@ -213,7 +218,6 @@ class Table(StrAndUnicode): """ 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 @@ -232,7 +236,8 @@ class Table(StrAndUnicode): @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): @@ -240,7 +245,8 @@ class Table(StrAndUnicode): @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): @@ -255,24 +261,24 @@ class Table(StrAndUnicode): 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 ```` tag when + """ + The attributes that should be applied to the ``
`` tag when rendering HTML. :rtype: :class:`~.utils.AttributeDict` object. - """ return self._meta.attrs diff --git a/django_tables/templates/django_tables/table.html b/django_tables/templates/django_tables/table.html index 21699bb..5c2e854 100644 --- a/django_tables/templates/django_tables/table.html +++ b/django_tables/templates/django_tables/table.html @@ -24,10 +24,10 @@ {% endfor %} - {% empty %} - {% if table.empty_text %} - - {% endif %} + {% empty %} + {% if table.empty_text %} + + {% endif %} {% endfor %}
{{ cell }}
{{ table.empty_text }}
{{ table.empty_text }}
diff --git a/docs/index.rst b/docs/index.rst index 23b198f..99975c9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -155,21 +155,67 @@ Any iterable can be used as table data, and there's builtin support for 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: @@ -222,9 +268,6 @@ a hook that allows abitrary attributes to be added to the ```` tag. >>> table.as_html() '
...' -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: @@ -264,12 +307,12 @@ arguments you're interested in, and the function will recieve them ... 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}]) @@ -305,9 +348,13 @@ ignore the built-in generation tools, and instead pass an instance of your {% for row in table.rows %} {% for cell in row %} - + {% endfor %} + {% empty %} + {% if table.empty_text %} + + {% endif %} {% endfor %}
{{ cell }}{{ cell }}
{{ table.empty_text }}
@@ -329,9 +376,8 @@ To change the way cells are rendered, simply override the >>> 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() @@ -349,6 +395,8 @@ To change the way cells are rendered, simply override the >>> table.as_html() u'
NormalAngry
May I have some food?GIVE ME THE FOOD NOW!
Hello!WHAT ARE YOU LOOKING AT?
\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: +-----------------------+--------------------------+ @@ -369,9 +417,8 @@ rendered). This can be achieved by using the :func:`mark_safe` function. >>> from django.utils.safestring import mark_safe >>> >>> class ImageColumn(tables.Column): - ... def render(self, **kwargs): - ... raw = super(AngryColumn, self).render(**kwargs) - ... return mark_safe('' % raw) + ... def render(self, value): + ... return mark_safe('' % value) ... @@ -551,7 +598,7 @@ API Reference ----------------------------- .. autoclass:: django_tables.columns.BoundColumns - :members: all, items, names, sortable, visible, __iter__, + :members: all, items, sortable, visible, __iter__, __contains__, __len__, __getitem__ @@ -566,7 +613,7 @@ API Reference -------------------------- .. autoclass:: django_tables.rows.BoundRows - :members: all, page, __iter__, __len__, count + :members: __iter__, __len__, count :class:`BoundRow` Objects