* Added ability to specify an empty_row value for tables
authorBradley Ayers <bradley.ayers@gmail.com>
Fri, 15 Apr 2011 10:22:18 +0000 (20:22 +1000)
committerBradley Ayers <bradley.ayers@gmail.com>
Fri, 15 Apr 2011 10:22:18 +0000 (20:22 +1000)
django_tables/columns.py
django_tables/tables.py
django_tables/templates/django_tables/table.html
docs/index.rst

index cf46a63c1cfe091ca68c1a3da395467090031699..1af2a81792dae25924baf879dd1379881e390f52 100644 (file)
@@ -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):
         ``<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)
@@ -154,7 +153,7 @@ class CheckBoxColumn(Column):
         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,
@@ -164,7 +163,6 @@ class CheckBoxColumn(Column):
         return mark_safe('<input %s/>' % 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 %} <template-tags.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
index bc92e9e6c484750444b44a98d0a03e0daa90d6a7..f3ba21e9ab59d2bb0ea6e9cccf913d6ff95082e1 100644 (file)
@@ -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 ``<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
 
index 21699bbfb6c62cd1df50308012a5ef4c932cd18d..5c2e854e71952523edf258b091f2f3715df37033 100644 (file)
                 <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>
index 23b198f0d08265bc6e588053b8090909f2e27479..99975c9a29bfab3dcadba18e0f0fa17d21a3dd61 100644 (file)
@@ -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 ``<table>`` tag.
     >>> 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:
 
@@ -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 %}
             <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>
@@ -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'<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:
 
 +-----------------------+--------------------------+
@@ -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('<img src="/media/img/%s.jpg" />' % raw)
+    ...     def render(self, value):
+    ...         return mark_safe('<img src="/media/img/%s.jpg" />' % 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