072f015e9d7334e24f63c3f344e4c28dc5fcb293
[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 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.
25
26
27 Slow start guide
28 ================
29
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:
32
33 .. code-block:: python
34
35     countries = [
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},
39     ]
40
41
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`.
45
46 .. code-block:: python
47
48     import django_tables as tables
49
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()
55
56
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.
59
60 .. code-block:: python
61
62     table = CountryTable(countries)
63
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:
66
67 .. code-block:: python
68
69     def home(request):
70         table = CountryTable(countries)
71         return render_to_response('home.html', {'table': table},
72                                   context_instances=RequestContext(request))
73
74 In your template, the easiest way to :term:`render` the table is via the
75 :meth:`~django_tables.tables.Table.as_html` method:
76
77 .. code-block:: django
78
79     {{ table.as_html }}
80
81 …which will render something like:
82
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 +--------------+------------+---------+--------+
92
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
95 template tag.
96
97 .. code-block:: django
98
99     {% load django_tables %}
100     {% render_table table %}
101
102 See :ref:`template-tags.render_table` for more information.
103
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.
108
109 .. code-block:: python
110
111     import django_tables as tables
112
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()
118
119         class Meta:
120             attrs = {'class': 'paleblue'}
121
122 The last thing to do is to include the stylesheet in the template.
123
124 .. code-block:: html
125
126     <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}django_tables/themes/paleblue/css/screen.css" />
127
128 Save your template and reload the page in your browser.
129
130
131 .. _table-data:
132
133 Table data
134 ==========
135
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.
138
139 .. code-block:: python
140
141     table = CountryTable(countries)              # valid
142     table = CountryTable(Country.objects.all())  # also valid
143
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.
148
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).
151
152
153 .. _ordering:
154
155 Ordering
156 ========
157
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.
161
162 .. code-block:: python
163
164     table = CountryTable(countries, order_by=('name', '-population'))
165     table = CountryTable(countries, order_by='name,-population')  # equivalant
166
167 Alternatively, the :attr:`~django_tables.tables.Table.order_by` attribute can
168 by modified.
169
170     table = CountryTable(countries)
171     table.order_by = ('name', '-population')
172     table.order_by = 'name,-population'  # equivalant
173
174
175 .. _pagination:
176
177 Pagination
178 ==========
179
180 Pagination is easy, just call :meth:`.Table.paginate` and pass in the current
181 page number, e.g.
182
183 .. code-block:: python
184
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))
190
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>`.
194
195 .. _custom-rendering:
196
197 Custom rendering
198 ================
199
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
202 flexibility.
203
204 CSS
205 ---
206
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.
210
211 .. code-block:: python
212
213     >>> import django_tables as tables
214     >>> class SimpleTable(tables.Table):
215     ...     id = tables.Column()
216     ...     age = tables.Column()
217     ...
218     ...     class Meta:
219     ...         attrs = {'class': 'mytable'}
220     ...
221     >>> table = SimpleTable()
222     >>> table.as_html()
223     '<table class="mytable">...'
224
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.
227
228 .. _table.render_foo:
229
230 .. _table.render_foo:
231
232 :meth:`Table.render_FOO` Methods
233 --------------------------------
234
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.
238
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
242 DRY).
243
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.
247
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``
254
255 .. code-block:: python
256
257     >>> import django_tables as tables
258     >>> class SimpleTable(tables.Table):
259     ...     row_number = tables.Column()
260     ...     id = tables.Column()
261     ...     age = tables.Column()
262     ...
263     ...     def render_row_number(self, **kwargs):
264     ...         value = getattr(self, '_counter', 0)
265     ...         self._counter = value + 1
266     ...         return 'Row %d' % value
267     ...
268     ...     def render_id(self, value, **kwargs):
269     ...         return '<%s>' % value
270     ...
271     >>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
272     >>> for cell in table.rows[0]:
273     ...     print cell
274     ...
275     Row 0
276     <10>
277     31
278
279
280 .. _custom-template:
281
282 Custom Template
283 ---------------
284
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:
288
289 .. code-block:: django
290
291     {% load django_tables %}
292     <table>
293         <thead>
294             <tr>
295             {% for column in table.columns %}
296                 <th><a href="{% set_url_param sort=column.name_toggled %}">{{ column }}</a></th>
297             {% endfor %}
298             </tr>
299         </thead>
300         <tbody>
301             {% for row in table.rows %}
302             <tr>
303                 {% for cell in row %}
304                     <td>{{ cell }}</td>
305                 {% endfor %}
306             </tr>
307             {% endfor %}
308         </tbody>
309     </table>
310
311
312 .. _subclassing-column:
313
314 Subclassing :class:`Column`
315 ---------------------------
316
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.
319
320 To change the way cells are rendered, simply override the
321 :meth:`~Column.render` method.
322
323 .. code-block:: python
324
325     >>> import django_tables as tables
326     >>>
327     >>> class AngryColumn(tables.Column):
328     ...     def render(self, *args, **kwargs):
329     ...         raw = super(AngryColumn, self).render(*args, **kwargs)
330     ...         return raw.upper()
331     ...
332     >>> class Example(tables.Table):
333     ...     normal = tables.Column()
334     ...     angry = AngryColumn()
335     ...
336     >>> data = [{
337     ...     'normal': 'May I have some food?',
338     ...     'angry': 'Give me the food now!',
339     ... }, {
340     ...     'normal': 'Hello!',
341     ...     'angry': 'What are you looking at?',
342     ... }]
343     ...
344     >>> table = Example(data)
345     >>> table.as_html()
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'
347
348 Which, when displayed in a browser, would look something like this:
349
350 +-----------------------+--------------------------+
351 | Normal                | Angry                    |
352 +=======================+==========================+
353 | May I have some food? | GIVE ME THE FOOD NOW!    |
354 +-----------------------+--------------------------+
355 | Hello!                | WHAT ARE YOU LOOKING AT? |
356 +-----------------------+--------------------------+
357
358
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.
362
363 .. code-block:: python
364
365     >>> from django.utils.safestring import mark_safe
366     >>>
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)
371     ...
372
373
374
375 .. _template_tags:
376
377 Template tags
378 =============
379
380 .. _template-tags.render_table:
381
382 render_table
383 ------------
384
385 Renders a :class:`~django_tables.tables.Table` object to HTML and includes as
386 many features as possible.
387
388 Sample usage:
389
390 .. code-block:: django
391
392     {% load django_tables %}
393     {% render_table table %}
394
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.
399
400
401 .. _template-tags.set_url_param:
402
403 set_url_param
404 -------------
405
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 %}``).
410
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.
414
415 Let's assume we have the querystring ``?search=pirates&sort=name&page=5`` and
416 we want to update the ``sort`` parameter:
417
418 .. code-block:: django
419
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
423
424
425
426 A table instance bound to data has two attributes ``columns`` and ``rows``,
427 which can be iterated over:
428
429 .. code-block:: django
430
431     <table>
432         <thead>
433             <tr>
434             {% for column in table.columns %}
435                 <th><a href="?sort={{ column.name_toggled }}">{{ column }}</a></th>
436             {% endfor %}
437             </tr>
438         </thead>
439         <tbody>
440         {% for row in table.rows %}
441             <tr>
442             {% for value in row %}
443                 <td>{{ value }}</td>
444             {% endfor %}
445             </tr>
446         {% endfor %}
447         </tbody>
448     </table>
449
450
451 API Reference
452 =============
453
454 :class:`Accessor` Objects:
455 --------------------------
456
457 .. autoclass:: django_tables.utils.Accessor
458     :members:
459
460
461 :class:`Table` Objects:
462 -----------------------
463
464 .. autoclass:: django_tables.tables.Table
465
466
467 :class:`Table.Meta` Objects:
468 ----------------------------
469
470 .. class:: Table.Meta
471
472     .. attribute:: attrs
473
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.
478
479         Default: ``{}``
480
481         :type: :class:`dict`
482
483     .. attribute:: sortable
484
485         Does the table support ordering?
486
487         Default: :const:`True`
488
489         :type: :class:`bool`
490
491     .. attribute:: order_by
492
493         The default ordering. e.g. ``('name', '-age')``
494
495         Default: ``()``
496
497         :type: :class:`tuple`
498
499
500 :class:`TableData` Objects:
501 ------------------------------
502
503 .. autoclass:: django_tables.tables.TableData
504     :members: __init__, order_by, __getitem__, __len__
505
506
507 :class:`TableOptions` Objects:
508 ------------------------------
509
510 .. autoclass:: django_tables.tables.TableOptions
511     :members:
512
513
514 :class:`Column` Objects:
515 ------------------------
516
517 .. autoclass:: django_tables.columns.Column
518
519
520 :class:`CheckBoxColumn` Objects:
521 --------------------------------
522
523 .. autoclass:: django_tables.columns.CheckBoxColumn
524     :members:
525
526
527 :class:`LinkColumn` Objects:
528 ----------------------------
529
530 .. autoclass:: django_tables.columns.LinkColumn
531     :members:
532
533
534 :class:`TemplateColumn` Objects:
535 --------------------------------
536
537 .. autoclass:: django_tables.columns.TemplateColumn
538     :members:
539
540
541 :class:`BoundColumns` Objects
542 -----------------------------
543
544 .. autoclass:: django_tables.columns.BoundColumns
545     :members: all, items, names, sortable, visible, __iter__,
546               __contains__, __len__, __getitem__
547
548
549 :class:`BoundColumn` Objects
550 ----------------------------
551
552 .. autoclass:: django_tables.columns.BoundColumn
553     :members:
554
555
556 :class:`BoundRows` Objects
557 --------------------------
558
559 .. autoclass:: django_tables.rows.BoundRows
560     :members: all, page, __iter__, __len__, count
561
562
563 :class:`BoundRow` Objects
564 -------------------------
565
566 .. autoclass:: django_tables.rows.BoundRow
567     :members: __getitem__, __contains__, __iter__, record, table
568
569
570 :class:`AttributeDict` Objects
571 ------------------------------
572
573 .. autoclass:: django_tables.utils.AttributeDict
574     :members:
575
576
577 :class:`OrderBy` Objects
578 ------------------------
579
580 .. autoclass:: django_tables.utils.OrderBy
581     :members:
582
583
584 :class:`OrderByTuple` Objects
585 -----------------------------
586
587 .. autoclass:: django_tables.utils.OrderByTuple
588     :members: __unicode__, __contains__, __getitem__, cmp
589
590
591 Glossary
592 ========
593
594 .. glossary::
595
596     accessor
597         Refers to an :class:`~django_tables.utils.Accessor` object
598
599     bare orderby
600         The non-prefixed form of an :class:`~django_tables.utils.OrderBy`
601         object. Typically the bare form is just the ascending form.
602
603         Example: ``age`` is the bare form of ``-age``
604
605     column name
606         The name given to a column. In the follow example, the *column name* is
607         ``age``.
608
609         .. code-block:: python
610
611             class SimpleTable(tables.Table):
612                 age = tables.Column()
613
614     table
615         The traditional concept of a table. i.e. a grid of rows and columns
616         containing data.
617
618     view
619         A Django view.
620
621     record
622         A single Python object used as the data for a single row.
623
624     render
625         The act of serialising a :class:`~django_tables.tables.Table` into
626         HTML.
627
628     template
629         A Django template.
630
631     table data
632         An interable of :term:`records <record>` that
633         :class:`~django_tables.tables.Table` uses to populate its rows.