3 ===============================================
4 django-tables - An app for creating HTML tables
5 ===============================================
7 django-tables simplifies the task of turning sets of datainto HTML tables. It
8 has native support for pagination and sorting. It does for HTML tables what
9 ``django.forms`` does for HTML forms.
14 1. Download and install from https://github.com/bradleyayers/django-tables.
15 Grab a ``.tar.gz`` of the latest tag, and run ``pip install <tar.gz>``.
16 2. Hook the app into your Django project by adding ``'django_tables'`` to your
17 ``INSTALLED_APPS`` setting.
18 3. Write a subclass of :class:`~django_tables.tables.Table` that describes the
19 structure of your table.
20 4. Create an instance of your table in a :term:`view`, provide it with
21 :term:`table data`, and pass it to a :term:`template` for display.
22 5. Use ``{{ table.as_html }}``, the
23 :ref:`template tag <template-tags.render_table>`, or your own
24 :ref:`custom template <custom-template>` to display the table.
30 We're going to take some data that describes three countries and
31 turn it into an HTML table. This is the data we'll be using:
33 .. code-block:: python
36 {'name': 'Australia', 'population': 21, 'tz': 'UTC +10', 'visits': 1},
37 {'name': 'Germany', 'population', 81, 'tz': 'UTC +1', 'visits': 2},
38 {'name': 'Mexico', 'population': 107, 'tz': 'UTC -6', 'visits': 0},
42 The first step is to subclass :class:`~django_tables.tables.Table` and describe
43 the table structure. This is done by creating a column for each attribute in
44 the :term:`table data`.
46 .. code-block:: python
48 import django_tables as tables
50 class CountryTable(tables.Table):
51 name = tables.Column()
52 population = tables.Column()
53 tz = tables.Column(verbose_name='Time Zone')
54 visits = tables.Column()
57 Now that we've defined our table, it's ready for use. We simply create an
58 instance of it, and pass in our table data.
60 .. code-block:: python
62 table = CountryTable(countries)
64 Now we add it to our template context and render it to HTML. Typically you'd
65 write a view that would look something like:
67 .. code-block:: python
70 table = CountryTable(countries)
71 return render_to_response('home.html', {'table': table},
72 context_instances=RequestContext(request))
74 In your template, the easiest way to :term:`render` the table is via the
75 :meth:`~django_tables.tables.Table.as_html` method:
77 .. code-block:: django
81 …which will render something like:
83 +--------------+------------+---------+--------+
84 | Country Name | Population | Tz | Visit |
85 +==============+============+=========+========+
86 | Australia | 21 | UTC +10 | 1 |
87 +--------------+------------+---------+--------+
88 | Germany | 81 | UTC +1 | 2 |
89 +--------------+------------+---------+--------+
90 | Mexico | 107 | UTC -6 | 0 |
91 +--------------+------------+---------+--------+
93 This approach is easy, but it's not fully featured. For slightly more effort,
94 you can render a table with sortable columns. For this, you must use the
97 .. code-block:: django
99 {% load django_tables %}
100 {% render_table table %}
102 See :ref:`template-tags.render_table` for more information.
104 The table will be rendered, but chances are it will still look quite ugly. An
105 easy way to make it pretty is to use the built-in *paleblue* theme. For this to
106 work, you must add a CSS class to the ``<table>`` tag. This can be achieved by
107 adding a ``class Meta:`` to the table class and defining a ``attrs`` variable.
109 .. code-block:: python
111 import django_tables as tables
113 class CountryTable(tables.Table):
114 name = tables.Column()
115 population = tables.Column()
116 tz = tables.Column(verbose_name='Time Zone')
117 visits = tables.Column()
120 attrs = {'class': 'paleblue'}
122 The last thing to do is to include the stylesheet in the template.
126 <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}django_tables/themes/paleblue/css/screen.css" />
128 Save your template and reload the page in your browser.
136 The data used to populate a table is called :term:`table data`. To provide a
137 table with data, pass it in as the first argument when instantiating a table.
139 .. code-block:: python
141 table = CountryTable(countries) # valid
142 table = CountryTable(Country.objects.all()) # also valid
144 Each item in the :term:`table data` is called a :term:`record` and is used to
145 populate a single row in the table. By default, the table uses column names
146 as :term:`accessors <accessor>` to retrieve individual cell values. This can
147 be changed via the :attr:`~django_tables.columns.Column.accessor` argument.
149 Any iterable can be used as table data, and there's builtin support for
150 :class:`QuerySet` objects (to ensure they're handled effeciently).
158 Changing the table ordering is easy. When creating a
159 :class:`~django_tables.tables.Table` object include an `order_by` parameter
160 with a tuple that describes the way the ordering should be applied.
162 .. code-block:: python
164 table = CountryTable(countries, order_by=('name', '-population'))
165 table = CountryTable(countries, order_by='name,-population') # equivalant
167 Alternatively, the :attr:`~django_tables.tables.Table.order_by` attribute can
170 table = CountryTable(countries)
171 table.order_by = ('name', '-population')
172 table.order_by = 'name,-population' # equivalant
180 Pagination is easy, just call :meth:`.Table.paginate` and pass in the current
183 .. code-block:: python
185 def people_listing(request):
186 table = PeopleTable(Person.objects.all())
187 table.paginate(page=request.GET.get('page', 1))
188 return render_to_response('people_listing.html', {'table': table},
189 context_instance=RequestContext(request))
191 The last set is to render the table. :meth:`.Table.as_html` doesn't support
192 pagination, so you must use :ref:`{% render_table %}
193 <template-tags.render_table>`.
195 .. _custom-rendering:
200 Various options are available for changing the way the table is :term:`rendered
201 <render>`. Each approach has a different balance of ease-of-use and
207 In order to use CSS to style a table, you'll probably want to add a
208 ``class`` or ``id`` attribute to the ``<table>`` element. ``django-tables`` has
209 a hook that allows abitrary attributes to be added to the ``<table>`` tag.
211 .. code-block:: python
213 >>> import django_tables as tables
214 >>> class SimpleTable(tables.Table):
215 ... id = tables.Column()
216 ... age = tables.Column()
219 ... attrs = {'class': 'mytable'}
221 >>> table = SimpleTable()
223 '<table class="mytable">...'
225 Inspired by Django's ORM, the ``class Meta:`` allows you to define extra
226 characteristics of a table. See :class:`Table.Meta` for details.
228 .. _table.render_foo:
230 .. _table.render_foo:
232 :meth:`Table.render_FOO` Methods
233 --------------------------------
235 If you want to adjust the way table cells in a particular column are rendered,
236 you can implement a ``render_FOO`` method. ``FOO`` is replaced with the
237 :term:`name <column name>` of the column.
239 This approach provides a lot of control, but is only suitable if you intend to
240 customise the rendering for a single table (otherwise you'll end up having to
241 copy & paste the method to every table you want to modify – which violates
244 For convenience, a bunch of commonly used/useful values are passed to
245 ``render_FOO`` functions, when writing the signature, accept the arguments
246 you're interested in, and collect the rest in a ``**kwargs`` argument.
248 :param value: the value for the cell retrieved from the :term:`table data`
249 :param record: the entire record for the row from :term:`table data`
250 :param column: the :class:`.Column` object
251 :param bound_column: the :class:`.BoundColumn` object
252 :param bound_row: the :class:`.BoundRow` object
253 :param table: alias for ``self``
255 .. code-block:: python
257 >>> import django_tables as tables
258 >>> class SimpleTable(tables.Table):
259 ... row_number = tables.Column()
260 ... id = tables.Column()
261 ... age = tables.Column()
263 ... def render_row_number(self, **kwargs):
264 ... value = getattr(self, '_counter', 0)
265 ... self._counter = value + 1
266 ... return 'Row %d' % value
268 ... def render_id(self, value, **kwargs):
269 ... return '<%s>' % value
271 >>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
272 >>> for cell in table.rows[0]:
285 And of course if you want full control over the way the table is rendered,
286 ignore the built-in generation tools, and instead pass an instance of your
287 :class:`Table` subclass into your own template, and render it yourself:
289 .. code-block:: django
291 {% load django_tables %}
295 {% for column in table.columns %}
296 <th><a href="{% set_url_param sort=column.name_toggled %}">{{ column }}</a></th>
301 {% for row in table.rows %}
303 {% for cell in row %}
312 .. _subclassing-column:
314 Subclassing :class:`Column`
315 ---------------------------
317 If you want to have a column behave the same way in many tables, it's best to
318 create a subclass of :class:`Column` and use that when defining the table.
320 To change the way cells are rendered, simply override the
321 :meth:`~Column.render` method.
323 .. code-block:: python
325 >>> import django_tables as tables
327 >>> class AngryColumn(tables.Column):
328 ... def render(self, *args, **kwargs):
329 ... raw = super(AngryColumn, self).render(*args, **kwargs)
330 ... return raw.upper()
332 >>> class Example(tables.Table):
333 ... normal = tables.Column()
334 ... angry = AngryColumn()
337 ... 'normal': 'May I have some food?',
338 ... 'angry': 'Give me the food now!',
340 ... 'normal': 'Hello!',
341 ... 'angry': 'What are you looking at?',
344 >>> table = Example(data)
346 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'
348 Which, when displayed in a browser, would look something like this:
350 +-----------------------+--------------------------+
352 +=======================+==========================+
353 | May I have some food? | GIVE ME THE FOOD NOW! |
354 +-----------------------+--------------------------+
355 | Hello! | WHAT ARE YOU LOOKING AT? |
356 +-----------------------+--------------------------+
359 If you plan on returning HTML from a :meth:`~Column.render` method, you must
360 remember to mark it as safe (otherwise it will be escaped when the table is
361 rendered). This can be achieved by using the :func:`mark_safe` function.
363 .. code-block:: python
365 >>> from django.utils.safestring import mark_safe
367 >>> class ImageColumn(tables.Column):
368 ... def render(self, **kwargs):
369 ... raw = super(AngryColumn, self).render(**kwargs)
370 ... return mark_safe('<img src="/media/img/%s.jpg" />' % raw)
380 .. _template-tags.render_table:
385 Renders a :class:`~django_tables.tables.Table` object to HTML and includes as
386 many features as possible.
390 .. code-block:: django
392 {% load django_tables %}
393 {% render_table table %}
395 This tag temporarily modifies the :class:`.Table` object while it is being
396 rendered. It adds a ``request`` attribute to the table, which allows
397 :class:`Column` objects to have access to a ``RequestContext``. See
398 :class:`.TemplateColumn` for an example.
401 .. _template-tags.set_url_param:
406 This template tag is a utility that allows you to update a portion of the
407 query-string without overwriting the entire thing. However you shouldn't need
408 to use this template tag unless you are rendering the table from scratch (i.e.
409 not using ``as_html()`` or ``{% render_table %}``).
411 This is very useful if you want the give your users the ability to interact
412 with your table (e.g. change the ordering), because you will need to create
413 urls with the appropriate queries.
415 Let's assume we have the querystring ``?search=pirates&sort=name&page=5`` and
416 we want to update the ``sort`` parameter:
418 .. code-block:: django
420 {% set_url_param sort="dob" %} # ?search=pirates&sort=dob&page=5
421 {% set_url_param sort="" %} # ?search=pirates&page=5
422 {% set_url_param sort="" search="" %} # ?page=5
426 A table instance bound to data has two attributes ``columns`` and ``rows``,
427 which can be iterated over:
429 .. code-block:: django
434 {% for column in table.columns %}
435 <th><a href="?sort={{ column.name_toggled }}">{{ column }}</a></th>
440 {% for row in table.rows %}
442 {% for value in row %}
454 :class:`Accessor` Objects:
455 --------------------------
457 .. autoclass:: django_tables.utils.Accessor
461 :class:`Table` Objects:
462 -----------------------
464 .. autoclass:: django_tables.tables.Table
467 :class:`Table.Meta` Objects:
468 ----------------------------
470 .. class:: Table.Meta
474 Allows custom HTML attributes to be specified which will be added to
475 the ``<table>`` tag of any table rendered via
476 :meth:`~django_tables.tables.Table.as_html` or the
477 :ref:`template-tags.render_table` template tag.
483 .. attribute:: sortable
485 Does the table support ordering?
487 Default: :const:`True`
491 .. attribute:: order_by
493 The default ordering. e.g. ``('name', '-age')``
497 :type: :class:`tuple`
500 :class:`TableData` Objects:
501 ------------------------------
503 .. autoclass:: django_tables.tables.TableData
504 :members: __init__, order_by, __getitem__, __len__
507 :class:`TableOptions` Objects:
508 ------------------------------
510 .. autoclass:: django_tables.tables.TableOptions
514 :class:`Column` Objects:
515 ------------------------
517 .. autoclass:: django_tables.columns.Column
520 :class:`CheckBoxColumn` Objects:
521 --------------------------------
523 .. autoclass:: django_tables.columns.CheckBoxColumn
527 :class:`LinkColumn` Objects:
528 ----------------------------
530 .. autoclass:: django_tables.columns.LinkColumn
534 :class:`TemplateColumn` Objects:
535 --------------------------------
537 .. autoclass:: django_tables.columns.TemplateColumn
541 :class:`BoundColumns` Objects
542 -----------------------------
544 .. autoclass:: django_tables.columns.BoundColumns
545 :members: all, items, names, sortable, visible, __iter__,
546 __contains__, __len__, __getitem__
549 :class:`BoundColumn` Objects
550 ----------------------------
552 .. autoclass:: django_tables.columns.BoundColumn
556 :class:`BoundRows` Objects
557 --------------------------
559 .. autoclass:: django_tables.rows.BoundRows
560 :members: all, page, __iter__, __len__, count
563 :class:`BoundRow` Objects
564 -------------------------
566 .. autoclass:: django_tables.rows.BoundRow
567 :members: __getitem__, __contains__, __iter__, record, table
570 :class:`AttributeDict` Objects
571 ------------------------------
573 .. autoclass:: django_tables.utils.AttributeDict
577 :class:`OrderBy` Objects
578 ------------------------
580 .. autoclass:: django_tables.utils.OrderBy
584 :class:`OrderByTuple` Objects
585 -----------------------------
587 .. autoclass:: django_tables.utils.OrderByTuple
588 :members: __unicode__, __contains__, __getitem__, cmp
597 Refers to an :class:`~django_tables.utils.Accessor` object
600 The non-prefixed form of an :class:`~django_tables.utils.OrderBy`
601 object. Typically the bare form is just the ascending form.
603 Example: ``age`` is the bare form of ``-age``
606 The name given to a column. In the follow example, the *column name* is
609 .. code-block:: python
611 class SimpleTable(tables.Table):
612 age = tables.Column()
615 The traditional concept of a table. i.e. a grid of rows and columns
622 A single Python object used as the data for a single row.
625 The act of serialising a :class:`~django_tables.tables.Table` into
632 An interable of :term:`records <record>` that
633 :class:`~django_tables.tables.Table` uses to populate its rows.