25a4401dcd8fb11e390486c1f0fd179d976025bf
[django-tables2.git] / docs / index.rst
1 .. default-domain:: py
2
3 =====================================================
4 django-tables - An app for creating HTML tables
5 =====================================================
6
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.
10
11 Quick start guide
12 =================
13
14 1. Download and install the package.
15 2. Install the tables framework by adding ``'django_tables'`` to your
16    ``INSTALLED_APPS`` setting.
17 3. Ensure that ``'django.core.context_processors.request'`` is in your
18    ``TEMPLATE_CONTEXT_PROCESSORS`` setting.
19 4. Write table classes for the types of tables you want to display.
20 5. Create an instance of a table in a view, provide it your data, and pass it
21    to a template for display.
22 6. Use ``{{ table.as_html }}``, the
23    :ref:`template tag <template_tags.render_table>`, or your own
24    custom template code to display the table.
25
26
27 Tables
28 ======
29
30 For each type of table you want to display, you will need to create a subclass
31 of ``django_tables.Table`` that describes the structure of the table.
32
33 In this example we are going to take some data describing three countries and
34 turn it into a HTML table. We start by creating our data:
35
36 .. code-block:: python
37
38     >>> countries = [
39     ...     {'name': 'Australia', 'population': 21, 'tz': 'UTC +10', 'visits': 1},
40     ...     {'name': 'Germany', 'population', 81, 'tz': 'UTC +1', 'visits': 2},
41     ...     {'name': 'Mexico', 'population': 107, 'tz': 'UTC -6', 'visits': 0},
42     ... ]
43
44 Next we subclass ``django_tables.Table`` to create a table that describes our
45 data. The API should look very familiar since it's based on Django's
46 database model API:
47
48 .. code-block:: python
49
50     >>> import django_tables as tables
51     >>> class CountryTable(tables.Table):
52     ...     name = tables.Column()
53     ...     population = tables.Column()
54     ...     tz = tables.Column(verbose_name='Time Zone')
55     ...     visits = tables.Column()
56
57
58 Providing data
59 --------------
60
61 To use the table, simply create an instance of the table class and pass in your
62 data. e.g. following on from the above example:
63
64 .. code-block:: python
65
66     >>> table = CountryTable(countries)
67
68 Tables have support for any iterable data that contains objects with
69 attributes that can be accessed as property or dictionary syntax:
70
71 .. code-block:: python
72
73     >>> table = SomeTable([{'a': 1, 'b': 2}, {'a': 4, 'b': 8}])  # valid
74     >>> table = SomeTable(SomeModel.objects.all())  # also valid
75
76 Each item in the data corresponds to one row in the table. By default, the
77 table uses column names as the keys (or attributes) for extracting cell values
78 from the data. This can be changed by using the :attr:`~Column.accessor`
79 argument.
80
81
82 Displaying a table
83 ------------------
84
85 There are two ways to display a table, the easiest way is to use the table's
86 own ``as_html`` method:
87
88 .. code-block:: django
89
90     {{ table.as_html }}
91
92 Which will render something like:
93
94 +--------------+------------+---------+
95 | Country Name | Population | Tz      |
96 +==============+============+=========+
97 | Australia    | 21         | UTC +10 |
98 +--------------+------------+---------+
99 | Germany      | 81         | UTC +1  |
100 +--------------+------------+---------+
101 | Mexico       | 107        | UTC -6  |
102 +--------------+------------+---------+
103
104 The downside of this approach is that pagination and sorting will not be
105 available. These features require the use of the ``{% render_table %}``
106 template tag:
107
108 .. code-block:: django
109
110     {% load django_tables %}
111     {% render_table table %}
112
113 See :ref:`template_tags` for more information.
114
115
116 Ordering
117 --------
118
119 Controlling the order that the rows are displayed (sorting) is simple, just use
120 the :attr:`~Table.order_by` property or pass it in when initialising the
121 instance:
122
123 .. code-block:: python
124
125     >>> # order_by argument when creating table instances
126     >>> table = CountryTable(countries, order_by='name, -population')
127     >>> table = CountryTable(countries, order_by=('name', '-population'))
128     >>> # order_by property on table instances
129     >>> table = CountryTable(countries)
130     >>> table.order_by = 'name, -population'
131     >>> table.order_by = ('name', '-population')
132
133
134 Customising the output
135 ======================
136
137 There are a number of options available for changing the way the table is
138 rendered. Each approach provides balance of ease-of-use and control (the more
139 control you want, the less easy it is to use).
140
141 CSS
142 ---
143
144 If you want to affect the appearance of the table using CSS, you probably want
145 to add a ``class`` or ``id`` attribute to the ``<table>`` element. This can be
146 achieved by specifying an ``attrs`` variable in the table's ``Meta`` class.
147
148 .. code-block:: python
149
150     >>> import django_tables as tables
151     >>> class SimpleTable(tables.Table):
152     ...     id = tables.Column()
153     ...     age = tables.Column()
154     ...
155     ...     class Meta:
156     ...         attrs = {'class': 'mytable'}
157     ...
158     >>> table = SimpleTable()
159     >>> table.as_html()
160     '<table class="mytable">...'
161
162 The :attr:`Table.attrs` property actually returns an :class:`AttributeDict`
163 object. These objects are identical to :class:`dict`, but have an
164 :meth:`AttributeDict.as_html` method that returns a HTML tag attribute string.
165
166 .. code-block:: python
167
168     >>> from django_tables.utils import AttributeDict
169     >>> attrs = AttributeDict({'class': 'mytable', 'id': 'someid'})
170     >>> attrs.as_html()
171     'class="mytable" id="someid"'
172
173 The returned string is marked safe, so it can be used safely in a template.
174
175 Column formatter
176 ----------------
177
178 Using a formatter is a quick way to adjust the way values are displayed in a
179 column. A limitation of this approach is that you *only* have access to a
180 single attribute of the data source.
181
182 To use a formatter, simply provide the :attr:`~Column.formatter` argument to a
183 :class:`Column` when you define the :class:`Table`:
184
185 .. code-block:: python
186
187     >>> import django_tables as tables
188     >>> class SimpleTable(tables.Table):
189     ...     id = tables.Column(formatter=lambda x: '#%d' % x)
190     ...     age = tables.Column(formatter=lambda x: '%d years old' % x)
191     ...
192     >>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
193     >>> row = table.rows[0]
194     >>> for cell in row:
195     ...     print cell
196     ...
197     #10
198     31 years old
199
200 As you can see, the only the value of the column is available to the formatter.
201 This means that **it's impossible create a formatter that incorporates other
202 values of the record**, e.g. a column with an ``<a href="...">`` that uses
203 :func:`reverse` with the record's ``pk``.
204
205 If formatters aren't powerful enough, you'll need to either :ref:`create a
206 Column subclass <subclassing-column>`, or to use the
207 :ref:`Table.render_FOO method <table.render_foo>`.
208
209
210 .. _table.render_foo:
211
212 :meth:`Table.render_FOO` Method
213 -------------------------------
214
215 This approach provides a lot of control, but is only suitable if you intend to
216 customise the rendering for a single table (otherwise you'll end up having to
217 copy & paste the method to every table you want to modify – which violates
218 DRY).
219
220 The example below has a number of different techniques in use:
221
222 * :meth:`Column.render` (accessible via :attr:`BoundColumn.column`) applies the
223   *formatter* if it's been provided. The effect of this behaviour can be seen
224   below in the output for the ``id`` column. Square brackets (from the
225   *formatter*) have been applied *after* the angled brackets (from the
226   :meth:`~Table.render_FOO`).
227 * Completely abitrary values can be returned by :meth:`render_FOO` methods, as
228   shown in :meth:`~SimpleTable.render_row_number` (a :attr:`_counter` attribute
229   is added to the :class:`SimpleTable` object to keep track of the row number).
230
231   This is possible because :meth:`render_FOO` methods override the default
232   behaviour of retrieving a value from the data-source.
233
234 .. code-block:: python
235
236     >>> import django_tables as tables
237     >>> class SimpleTable(tables.Table):
238     ...     row_number = tables.Column()
239     ...     id = tables.Column(formatter=lambda x: '[%s]' % x)
240     ...     age = tables.Column(formatter=lambda x: '%d years old' % x)
241     ...
242     ...     def render_row_number(self, bound_column, bound_row):
243     ...         value = getattr(self, '_counter', 0)
244     ...         self._counter = value + 1
245     ...         return 'Row %d' % value
246     ...
247     ...     def render_id(self, bound_column, bound_row):
248     ...         value = bound_column.column.render(table=self,
249     ...                                            bound_column=bound_column,
250     ...                                            bound_row=bound_row)
251     ...         return '<%s>' % value
252     ...
253     >>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
254     >>> for cell in table.rows[0]:
255     ...     print cell
256     ...
257     Row 0
258     <[10]>
259     31 years old
260
261 The :meth:`Column.render` method is what actually performs the lookup into a
262 record to retrieve the column value. In the example above, the
263 :meth:`render_row_number` never called :meth:`Column.render` and as a result
264 there was not attempt to access the data source to retrieve a value.
265
266
267 Custom Template
268 ---------------
269
270 And of course if you want full control over the way the table is rendered,
271 ignore the built-in generation tools, and instead pass an instance of your
272 :class:`Table` subclass into your own template, and render it yourself:
273
274 .. code-block:: django
275
276     {% load django_tables %}
277     <table>
278         <thead>
279             <tr>
280             {% for column in table.columns %}
281                 <th><a href="{% set_url_param sort=column.name_toggled %}">{{ column }}</a></th>
282             {% endfor %}
283             </tr>
284         </thead>
285         <tbody>
286             {% for row in table.rows %}
287             <tr>
288                 {% for cell in row %}
289                     <td>{{ cell }}</td>
290                 {% endfor %}
291             </tr>
292             {% endfor %}
293         </tbody>
294     </table>
295
296
297 .. _subclassing-column:
298
299 Subclassing :class:`Column`
300 ---------------------------
301
302 If you want to have a column behave the same way in many tables, it's best to
303 create a subclass of :class:`Column` and use that when defining the table.
304
305 To change the way cells are rendered, simply override the
306 :meth:`~Column.render` method.
307
308 .. code-block:: python
309
310     >>> import django_tables as tables
311     >>>
312     >>> class AngryColumn(tables.Column):
313     ...     def render(self, *args, **kwargs):
314     ...         raw = super(AngryColumn, self).render(*args, **kwargs)
315     ...         return raw.upper()
316     ...
317     >>> class Example(tables.Table):
318     ...     normal = tables.Column()
319     ...     angry = AngryColumn()
320     ...
321     >>> data = [{
322     ...     'normal': 'May I have some food?',
323     ...     'angry': 'Give me the food now!',
324     ... }, {
325     ...     'normal': 'Hello!',
326     ...     'angry': 'What are you looking at?',
327     ... }]
328     ...
329     >>> table = Example(data)
330     >>> table.as_html()
331     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'
332
333 Which, when displayed in a browser, would look something like this:
334
335 +-----------------------+--------------------------+
336 | Normal                | Angry                    |
337 +=======================+==========================+
338 | May I have some food? | GIVE ME THE FOOD NOW!    |
339 +-----------------------+--------------------------+
340 | Hello!                | WHAT ARE YOU LOOKING AT? |
341 +-----------------------+--------------------------+
342
343
344 If you plan on returning HTML from a :meth:`~Column.render` method, you must
345 remember to mark it as safe (otherwise it will be escaped when the table is
346 rendered). This can be achieved by using the :func:`mark_safe` function.
347
348 .. code-block:: python
349
350     >>> from django.utils.safestring import mark_safe
351     >>>
352     >>> class ImageColumn(tables.Column):
353     ...     def render(self, **kwargs):
354     ...         raw = super(AngryColumn, self).render(**kwargs)
355     ...         return mark_safe('<img src="/media/img/%s.jpg" />' % raw)
356     ...
357
358
359
360 .. _template_tags:
361
362 Template tags
363 =============
364
365 .. _template_tags.render_table:
366
367 render_table
368 ------------
369
370 If you want to render a table that provides support for sorting and pagination,
371 you must use the ``{% render_table %}`` template tag. In this example ``table``
372 is an instance of a :class:`django_tables.Table` that has been put into the
373 template context:
374
375 .. code-block:: django
376
377     {% load django_tables %}
378     {% render_table table %}
379
380
381 .. _template_tags.set_url_param:
382
383 set_url_param
384 -------------
385
386 This template tag is a utility that allows you to update a portion of the
387 query-string without overwriting the entire thing. However you shouldn't need
388 to use this template tag unless you are rendering the table from scratch (i.e.
389 not using ``as_html()`` or ``{% render_table %}``).
390
391 This is very useful if you want the give your users the ability to interact
392 with your table (e.g. change the ordering), because you will need to create
393 urls with the appropriate queries.
394
395 Let's assume we have the query-string
396 ``?search=pirates&sort=name&page=5`` and we want to update the ``sort``
397 parameter:
398
399 .. code-block:: django
400
401     {% set_url_param sort="dob" %}         # ?search=pirates&sort=dob&page=5
402     {% set_url_param sort="" %}            # ?search=pirates&page=5
403     {% set_url_param sort="" search="" %}  # ?page=5
404
405
406
407 A table instance bound to data has two attributes ``columns`` and ``rows``,
408 which can be iterated over:
409
410 .. code-block:: django
411
412     <table>
413         <thead>
414             <tr>
415             {% for column in table.columns %}
416                 <th><a href="?sort={{ column.name_toggled }}">{{ column }}</a></th>
417             {% endfor %}
418             </tr>
419         </thead>
420         <tbody>
421         {% for row in table.rows %}
422             <tr>
423             {% for value in row %}
424                 <td>{{ value }}</td>
425             {% endfor %}
426             </tr>
427         {% endfor %}
428         </tbody>
429     </table>
430
431
432 API Reference
433 =============
434
435 :class:`Table` Objects:
436 ------------------------
437
438 .. autoclass:: django_tables.tables.Table
439     :members:
440
441
442 :class:`TableOptions` Objects:
443 ------------------------------
444
445 .. autoclass:: django_tables.tables.TableOptions
446     :members:
447
448
449 :class:`Column` Objects:
450 ------------------------
451
452 .. autoclass:: django_tables.columns.Column
453     :members: __init__, default, render
454
455
456 :class:`Columns` Objects
457 ------------------------
458
459 .. autoclass:: django_tables.columns.Columns
460     :members: __init__, all, items, names, sortable, visible, __iter__,
461               __contains__, __len__, __getitem__
462
463
464 :class:`BoundColumn` Objects
465 ----------------------------
466
467 .. autoclass:: django_tables.columns.BoundColumn
468     :members: __init__, table, column, name, accessor, default, formatter,
469               sortable, verbose_name, visible
470
471
472 :class:`Rows` Objects
473 ---------------------
474
475 .. autoclass:: django_tables.rows.Rows
476     :members: __init__, all, page, __iter__, __len__, count, __getitem__
477
478
479 :class:`BoundRow` Objects
480 -------------------------
481
482 .. autoclass:: django_tables.rows.BoundRow
483     :members: __init__, __getitem__, __contains__, __iter__, record, table
484
485
486 :class:`AttributeDict` Objects
487 ------------------------------
488
489 .. autoclass:: django_tables.utils.AttributeDict
490     :members:
491
492
493 :class:`OrderBy` Objects
494 ------------------------
495
496 .. autoclass:: django_tables.utils.OrderBy
497     :members:
498
499
500 :class:`OrderByTuple` Objects
501 -----------------------------
502
503 .. autoclass:: django_tables.utils.OrderByTuple
504     :members: __contains__, __getitem__, __unicode__
505
506
507 Glossary
508 ========
509
510 .. glossary::
511
512     table
513         The traditional concept of a table. i.e. a grid of rows and columns
514         containing data.