django-tables2 - An app for creating HTML tables

django-tables2 simplifies transforming data into HTML tables. It does for HTML tables what django.forms does for HTML forms. Features:

  • Pagination
  • Column based data ordering
  • Built-in columns for common use-cases
  • Easily extendable via subclassing
  • Extendable template
  • Generic view
  • QuerySet support
  • Built-in Django admin style theme (but can be easily remove).
  • ModelTable support (think django.forms.ModelForm)

It’s available in a few places, feedback is always welcome.

Tutorial

  1. pip install django-tables2
  2. Add 'django_tables2' to INSTALLED_APPS

Find some data that you’d like to render as a table. A QuerySet will work, but ease of demonstration we’ll use a list of dicts:

countries = [
    {'name': 'Australia', 'population': 21, 'tz': 'UTC +10', 'visits': 1},
    {'name': 'Germany', 'population': 81, 'tz': 'UTC +1', 'visits': 2},
    {'name': 'Mexico', 'population': 107, 'tz': 'UTC -6', 'visits': 0},
]

First step is it write a Table class to describe the structure:

import django_tables2 as tables

class CountryTable(tables.Table):
    name = tables.Column()
    population = tables.Column()
    tz = tables.Column(verbose_name='time zone')
    visits = tables.Column()

Now instantiate the table and pass in the data, then pass it to a template:

def home(request):
    table = CountryTable(countries)
    return render(request, 'home.html', {'table': table})

Render the table in the template using the built-in template tag.

{% load render_table from django_tables2 %}
{% render_table table %}

…which will give you somethinglike:

Country Name Population Time Zone Visit
Australia 21 UTC +10 1
Germany 81 UTC +1 2
Mexico 107 UTC -6 0

Note

{% render_table %} requires that the TEMPLATE_CONTEXT_PROCESSORS setting contains "django.core.context_processors.request". See render_table for details.

To enable ordering and pagination, use a RequestConfig object in the view:

from django_tables2 import RequestConfig

def home(request):
    table = CountryTable(countries)
    RequestConfig(request).configure(table)
    return render(request, 'home.html', {'table': table})

See Ordering, and Pagination for more information.

The table will be rendered, but chances are it will still look quite ugly. An easy way to make it pretty is to use the built-in paleblue theme. For this to work, you must add a CSS class to the <table> tag. This can be achieved by adding a class Meta: to the table class and defining a attrs variable.

import django_tables2 as tables

class CountryTable(tables.Table):
    name = tables.Column()
    population = tables.Column()
    tz = tables.Column(verbose_name='time zone')
    visits = tables.Column()

    class Meta:
        attrs = {'class': 'paleblue'}

The last thing to do is to include the stylesheet in the template.

<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}django_tables2/themes/paleblue/css/screen.css" />

Save your template and reload the page in your browser.

Table data

The data used to populate a table is called table data. To provide a table with data, pass it in as the first argument when instantiating a table.

Each item in the table data is called a record and is used to populate a single row in the table. By default, the table uses column names as accessors to retrieve individual cell values. This can be changed via the accessor argument.

Any iterable can be used as table data, and there’s builtin support for QuerySet objects (to ensure they’re handled effeciently).

Ordering

Note

If you want to change the order in which columns are displayed, see Table.Meta.sequence. Alternatively if you’re interested in the ordering of records within the table, read on.

Changing the way records in a table are ordered is easy and can be controlled via the order_by option. This can be configured in three places:

  1. Table.Meta.order_by
  2. Table(..., order_by=...)
  3. Table(...).order_by = ...

Each of the above options takes prescendent over the previous.

The value must be an iterable (or comma separated string) of order by alias.

Ordering preference is passed via the querystring in a variable. The name of the variable is determined by order_by_field (default: sort). This can be configured in three places:

  1. Table.Meta.order_by_field
  2. Table(..., order_by_field=...)
  3. Table(...).order_by_field = ...

RequestConfig honors these values and does the right thing.

Specifing ordering accessors for a column

In scenarios where you don’t want to use the column’s accessor value for sorting table data, it’s possible to specify alternatives. e.g.:

class Person(models.Model):
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)

    def name(self):
        return "{} {}".format(self.first_name, self.last_name)


class PersonTable(tables.Table):
    name = tables.Column(order_by=("last_name", "first_name"))

In the above example order_by needs to be specified, else the table would try to execute .order_by('name') on the queryset when the table is ordered. This would fail because name isn’t a field on the model.

Disabling ordering for specific columns

By default all table columns support ordering. This means that all the column headers are rendered as links which allow the user to adjust the ordering of the table data.

Ordering can be disabled on a table or column basis.

  • Table.Meta.orderable = False – default to disable ordering on columns
  • Column(orderable=False) – disable ordering for specific column

e.g. disable columns on all but one:

class SimpleTable(tables.Table):
    name = tables.Column()
    rating = tables.Column(orderable=True)

    class Meta:
        orderable = False

Non-queryset data ordering

Where the table is backed by a model, the database will handle the ordering. Where this is not the case, the Python cmp function is used and the following mechanism is used as a fallback when comparing across different types:

def cmp_(x, y):
    try:
        return cmp(x, y)
    except TypeError:
        return cmp((repr(type(x)), id(type(x)), x),
                   (repr(type(y)), id(type(y)), y))

Column headers

The header cell for each column comes from the column’s header() method. By default this method returns a titlised version of the column’s verbose_name.

When using queryset data and a verbose name hasn’t been explicitly defined for a column, the corresponding model field’s verbose name will be used.

Consider the following:

>>> class Person(models.Model):
...     first_name = models.CharField(verbose_name='model verbose name', max_length=200)
...     last_name = models.CharField(max_length=200)
...     region = models.ForeignKey('Region')
...
>>> class Region(models.Model):
...     name = models.CharField(max_length=200)
...
>>> class PersonTable(tables.Table):
...     first_name = tables.Column()
...     ln = tables.Column(accessor='last_name')
...     region_name = tables.Column(accessor='region.name')
...
>>> table = PersonTable(Person.objects.all())
>>> table.columns['first_name'].header
u'Model Verbose Name'
>>> table.columns['ln'].header
u'Last Name'
>>> table.columns['region_name'].header
u'Name'

As you can see in the last example (region name), the results are not always desirable when an accessor is used to cross relationships. To get around this be careful to define a verbose_name on such columns.

Custom rendering

Various options are available for changing the way the table is rendered. Each approach has a different balance of ease-of-use and flexibility.

CSS

In order to use CSS to style a table, you’ll probably want to add a class or id attribute to the <table> element. django-tables2 has a hook that allows abitrary attributes to be added to the <table> tag.

>>> import django_tables2 as tables
>>> class SimpleTable(tables.Table):
...     id = tables.Column()
...     age = tables.Column()
...
...     class Meta:
...         attrs = {'class': 'mytable'}
...
>>> table = SimpleTable()
>>> table.as_html()
'<table class="mytable">...'

Table.render_FOO() Methods

If you want to adjust the way table cells in a particular column are rendered, you can implement a render_FOO method. FOO should be the name of the column.

This approach provides a lot of control, but is only suitable if you intend to customise the rendering for a single table (otherwise you’ll end up having to copy & paste the method to every table you want to modify – which violates DRY).

Supported keyword arguments include: (only the arguments declared will be passed)

  • record – the entire record for the row from the table data
  • value – the value for the cell retrieved from the table data
  • column – the Column object
  • bound_column – the BoundColumn object
  • bound_row – the BoundRow object
  • table – alias for self

Example:

>>> import django_tables2 as tables
>>> class SimpleTable(tables.Table):
...     row_number = tables.Column()
...     id = tables.Column()
...     age = tables.Column()
...
...     def render_row_number(self):
...         value = getattr(self, '_counter', 0)
...         self._counter = value + 1
...         return 'Row %d' % value
...
...     def render_id(self, value):
...         return '<%s>' % value
...
>>> table = SimpleTable([{'age': 31, 'id': 10}, {'age': 34, 'id': 11}])
>>> for cell in table.rows[0]:
...     print cell
...
Row 0
<10>
31

Note

Due to the implementation of dynamic argument passing, any “catch-extra” arguments (e.g. *args or **kwargs) will not recieve any arguments. This is because inspect.getargsspec() is used to check what arguments a render_FOO method expect, and only to supply those.

Querystring fields

Tables pass data via the querystring to indicate ordering and pagination preferences.

The names of the querystring variables are configurable via the options:

  • order_by_field – default: sort
  • page_field – default: page
  • per_page_field – default: per_page, note: this field currently isn’t used by {% render_table %}

Each of these can be specified in three places:

  • Table.Meta.foo
  • Table(..., foo=...)
  • Table(...).foo = ...

If you’re using multiple tables on a single page, you’ll want to prefix these fields with a table-specific name. e.g.

def people_listing(request):
    config = RequestConfig(request)
    table1 = PeopleTable(Person.objects.all(), prefix="1-")  # prefix specified
    table2 = PeopleTable(Person.objects.all(), prefix="2-")  # prefix specified
    config.configure(table1)
    config.configure(table2)
    return render(request, "people_listing.html",
                  {"table1": table1, "table2": table2})

Column attributes

Column attributes can be specified using the Attrs object. An Attrs object defines HTML tag attributes for one of more elements within the column. Depending on the column, different elements are supported, however th and td are supported universally.

e.g.

>>> from django_tables2 import Attrs
>>> import django_tables2 as tables
>>>
>>> class SimpleTable(tables.Table):
...     name = tables.Column(attrs=Attrs(th={"id": "foo"}))
...
>>> SimpleTable(data).as_html()
"{snip}<thead><tr><th id="foo" class="name">{snip}<tbody><tr><td class="name">{snip}"

th and td are special cases because they’re extended during rendering to add the column name as a class. This is done to make writing CSS easier. Have a look at each column’s API reference to find which elements are supported.

Built-in columns

For common use-cases the following columns are included:

Subclassing Column

If you want to have a column behave the same way in many tables, it’s best to create a subclass of Column and use that when defining the table.

To change the way cells are rendered, simply override the render() method.

>>> import django_tables2 as tables
>>>
>>> class AngryColumn(tables.Column):
...     def render(self, value):
...         return value.upper()
...
>>> class Example(tables.Table):
...     normal = tables.Column()
...     angry = AngryColumn()
...
>>> data = [{
...     'normal': 'May I have some food?',
...     'angry': 'Give me the food now!',
... }, {
...     'normal': 'Hello!',
...     'angry': 'What are you looking at?',
... }]
...
>>> table = Example(data)
>>> 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 Table.render_FOO() Methods for a list of arguments that can be accepted.

Which, when displayed in a browser, would look something like this:

Normal Angry
May I have some food? GIVE ME THE FOOD NOW!
Hello! WHAT ARE YOU LOOKING AT?

For complicated columns, it’s sometimes necessary to return HTML from a render() method, but the string must be marked as safe (otherwise it will be escaped when the table is rendered). This can be achieved by using the mark_safe() function.

>>> from django.utils.safestring import mark_safe
>>>
>>> class ImageColumn(tables.Column):
...     def render(self, value):
...         return mark_safe('<img src="/media/img/%s.jpg" />' % value)
...

Custom Template

And of course if you want full control over the way the table is rendered, ignore the built-in generation tools, and instead pass an instance of your Table subclass into your own template, and render it yourself.

Have a look at django_tables2/templates/django_tables2/table.html for an example.

Template tags

render_table

Renders a Table object to HTML and enables as many features in the output as possible.

{% load django_tables2 %}
{% render_table table %}

{# Alternatively a specific template can be used #}
{% render_table table "path/to/custom_table_template.html" %}

If the second argument (template path) is given, the template will be rendered with a RequestContext and the table will be in the variable table.

Note

This tag temporarily modifies the Table object while it is being rendered. It adds a request attribute to the table, which allows Column objects to have access to a RequestContext. See TemplateColumn for an example.

This tag requires that the template in which it’s rendered contains the HttpRequest inside a request variable. This can be achieved by ensuring the TEMPLATE_CONTEXT_PROCESSORS setting contains "django.core.context_processors.request". By default it is not included, and the setting itself is not even defined within your project’s settings.py. To resolve this simply add the following to your settings.py:

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.static",
    "django.contrib.messages.context_processors.messages",
    "django.core.context_processors.request",
)

querystring

A utility that allows you to update a portion of the query-string without overwriting the entire thing.

Let’s assume we have the querystring ?search=pirates&sort=name&page=5 and we want to update the sort parameter:

{% querystring "sort"="dob" %}           # ?search=pirates&sort=dob&page=5
{% querystring "sort"="" %}              # ?search=pirates&page=5
{% querystring "sort"="" "search"="" %}  # ?page=5

{% with "search" as key %}               # supports variables as keys
{% querystring key="robots" %}           # ?search=robots&page=5
{% endwith %}

Template filters

title

String filter that performs title case conversion on a per-word basis, leaving words containing upper-case letters alone.

{{ "start 6PM"|title }}   # Start 6PM
{{ "sTart 6pm"|title }}   # sTart 6pm

Warning

Be careful when loading the django_tables2 template library to not in advertantly load title. You should always use the {% load ... from ... %} syntax.

Class Based Generic Mixins

Django 1.3 introduced class based views as a mechanism to reduce the repetition in view code. django-tables2 comes with a single class based view mixin: SingleTableMixin. It makes it trivial to incorporate a table into a view/template.

The following view parameters are supported:

  • table_class –- the table class to use, e.g. SimpleTable
  • table_data (or get_table_data()) – the data used to populate the table
  • context_table_name – the name of template variable containing the table object
  • table_pagination – pagination options to pass to RequestConfig

For example:

from django_tables2 import SingleTableView


class Person(models.Model):
    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)


class PersonTable(tables.Table):
    class Meta:
        model = Simple


class PersonList(SingleTableView):
    model = Person
    table_class = PersonTable

The template could then be as simple as:

{% load render_table from django_tables2 %}
{% render_table table %}

Such little code is possible due to the example above taking advantage of default values and SimpleTableMixin‘s eagarness at finding data sources when one isn’t explicitly defined.

Note

If you need more than one table on a page, use SingleTableView and use get_context_data() to initialise the other tables and add them to the context.

Note

You don’t have to base your view on ListView, you’re able to mix SingleTableMixin directly.

Table Mixins

It’s possible to create a mixin for a table that overrides something, however unless it itself is a subclass of Table class variable instances of Column will not be added to the class which is using the mixin.

Example:

>>> class UselessMixin(object):
...     extra = tables.Column()
...
>>> class TestTable(UselessMixin, tables.Table):
...     name = tables.Column()
...
>>> TestTable.base_columns.keys()
['name']

To have a mixin contribute a column, it needs to be a subclass of Table. With this in mind the previous example should have been written as follows:

>>> class UsefulMixin(tables.Table):
...     extra = tables.Column()
...
>>> class TestTable(UsefulMixin, tables.Table):
...     name = tables.Column()
...
>>> TestTable.base_columns.keys()
['extra', 'name']

Tables for models

Most of the time you’ll probably be making tables to display queryset data, and writing such tables involves a lot of duplicate code, e.g.:

>>> class Person(models.Model):
...     first_name = models.CharField(max_length=200)
...     last_name = models.CharField(max_length=200)
...     user = models.ForeignKey("auth.User")
...     dob = models.DateField()
...
>>> class PersonTable(tables.Table):
...     first_name = tables.Column()
...     last_name = tables.Column()
...     user = tables.Column()
...     dob = tables.Column()
...

Often a table will become quite complex after time, e.g. table.render_foo, changing verbose_name on columns, or adding an extra CheckBoxColumn.

django-tables2 offers the Table.Meta.model option to ease the pain. The model option causes the table automatically generate columns for the fields in the model. This means that the above table could be re-written as follows:

>>> class PersonTable(tables.Table):
...     class Meta:
...         model = Person
...
>>> PersonTable.base_columns.keys()
['first_name', 'last_name', 'user', 'dob']

If you want to customise one of the columns, simply define it the way you would normally:

>>> from django_tables2 import A
>>> class PersonTable(tables.Table):
...     user = tables.LinkColumn("admin:auth_user_change", args=[A("user.pk")])
...
...     class Meta:
...         model = Person
...
>>> PersonTable.base_columns.keys()
['first_name', 'last_name', 'dob', 'user']

It’s not immediately obvious but if you look carefully you’ll notice that the order of the fields has now changed – user is now last, rather than dob. This follows the same behaviour of Django’s model forms, and can be fixed in a similar way – the Table.Meta.sequence option:

>>> class PersonTable(tables.Table):
...     user = tables.LinkColumn("admin:auth_user_change", args=[A("user.pk")])
...
...     class Meta:
...         model = Person
...         sequence = ("first_name", "last_name", "user", "dob")
...
>>> PersonTable.base_columns.keys()
['first_name', 'last_name', 'user', 'dob']

… or use a shorter approach that makes use of the special "..." item:

>>> class PersonTable(tables.Table):
...     user = tables.LinkColumn("admin:auth_user_change", args=[A("user.pk")])
...
...     class Meta:
...         model = Person
...         sequence = ("...", "dob")
...
>>> PersonTable.base_columns.keys()
['first_name', 'last_name', 'user', 'dob']

API Reference

Accessor (A) Objects:

class django_tables2.utils.Accessor

A string describing a path from one object to another via attribute/index accesses. For convenience, the class has an alias A to allow for more concise code.

Relations are separated by a . character.

Attrs Objects:

class django_tables2.utils.Attrs

A collection of AttributeDict, each given a key.

This class is used as a container to hold differenct sets of attributes for a given column. Keys indicate where the attributes should be used, and support varies depending on the column.

It’s used in favour of a standard dict to enable backwards compatibility. Before it was introduced, columns had an attrs parameter that would be given a dict and would assign it to a single (typically input) element. The new approach allows attributes to be specified for multiple elements. By using the Attrs class your intention to use the new mechanism is explicit.

RequestConfig Objects:

class django_tables2.config.RequestConfig(request, paginate=True)

A configurator that uses request data to setup a table.

Parameters:paginate (dict or bool) – indicates whether to paginate, and if so, what default values to use. If the value evaluates to False, pagination will be disabled. A dict can be used to specify default values for the call to tables.Table.paginate() (e.g. to define a default per_page value).

Table Objects:

class django_tables2.tables.Table(data, order_by=None, orderable=None, empty_text=None, exclude=None, attrs=None, sequence=None, prefix=None, order_by_field=None, page_field=None, per_page_field=None, template=None, sortable=None, default=None)

A collection of columns, plus their associated data rows.

Parameters:
  • attrs (dict) – A mapping of attributes to values that will be added to the HTML <table> tag.
  • data (list or QuerySet-like) – The table data.
  • exclude (iterable) – A list of columns to be excluded from this table.
  • order_by (None, tuple or string) – sort the table based on these columns prior to display. (default Table.Meta.order_by)
  • order_by_field (string or None) – The name of the querystring field used to control the table ordering.
  • page_field (string or None) – The name of the querystring field used to control which page of the table is displayed (used when a table is paginated).
  • per_page_field (string or None) – The name of the querystring field used to control how many records are displayed on each page of the table.
  • prefix (string) – A prefix used on querystring arguments to allow multiple tables to be used on a single page, without having conflicts between querystring arguments. Depending on how the table is rendered, will determine how the prefix is used. For example {% render_table %} uses <prefix>-<argument>.
  • sequence (iterable) – The sequence/order of columns the columns (from left to right). Items in the sequence must be column names, or the remaining items symbol marker "..." (string containing three periods). If this marker is used, not all columns need to be defined.
  • orderable (bool) – Enable/disable column ordering on this table
  • template (string) – the template to render when using {% render_table %} (default django_tables2/table.html)
  • empty_text (string) – Empty text to render when the table has no data. (default Table.Meta.empty_text)
  • default (unicode) – Text to render in empty cells (determined by Column.empty_values, default :attrs:`.Table.Meta.default`)
TableDataClass

alias of TableData

as_html()

Render the table to a simple HTML table.

If this method is used in the request/response cycle, any links generated will clobber the querystring of the request. Use the {% render_table %} template tag instead.

attrs

The attributes that should be applied to the <table> tag when rendering HTML.

Return type:AttributeDict object.
paginate(klass=<class 'django.core.paginator.Paginator'>, per_page=None, page=1, *args, **kwargs)

Paginates the table using a paginator and creates a page property containing information for the current page.

Parameters:
  • klass (Paginator class) – a paginator class to paginate the results
  • per_page (int) – how many records are displayed on each page
  • page (int) – which page should be displayed.

Table.Meta Objects:

class Table.Meta

Provides a way to define global settings for table, as opposed to defining them for each instance.

attrs

Allows custom HTML attributes to be specified which will be added to the <table> tag of any table rendered via Table.as_html() or the render_table template tag.

Type :dict
Default :{}

This is typically used to enable a theme for a table (which is done by adding a CSS class to the <table> element). i.e.:

class SimpleTable(tables.Table):
    name = tables.Column()

    class Meta:
        attrs = {"class": "paleblue"}

Note

This functionality is also available via the attrs keyword argument to a table’s constructor.

empty_text

Defines the text to display when the table has no rows.

Type :string
Default :None

If the table is empty and bool(empty_text) is True, a row is displayed containing empty_text. This is allows a message such as There are currently no FOO. to be displayed.

Note

This functionality is also available via the empty_text keyword argument to a table’s constructor.

exclude

Defines which columns should be excluded from the table. This is useful in subclasses to exclude columns in a parent.

Type :tuple of string objects
Default :()

Example:

>>> class Person(tables.Table):
...     first_name = tables.Column()
...     last_name = tables.Column()
...
>>> Person.base_columns
{'first_name': <django_tables2.columns.Column object at 0x10046df10>,
'last_name': <django_tables2.columns.Column object at 0x10046d8d0>}
>>> class ForgetfulPerson(Person):
...     class Meta:
...         exclude = ("last_name", )
...
>>> ForgetfulPerson.base_columns
{'first_name': <django_tables2.columns.Column object at 0x10046df10>}

Note

This functionality is also available via the exclude keyword argument to a table’s constructor.

However, unlike some of the other Meta options, providing the exclude keyword to a table’s constructor won’t override the Meta.exclude. Instead, it will be effectively be added to it. i.e. you can’t use the constructor’s exclude argument to undo an exclusion.

model

A model to inspect and automatically create corresponding columns.

Type :Django model
Default :None

This option allows a Django model to be specified to cause the table to automatically generate columns that correspond to the fields in a model.

order_by

The default ordering. e.g. ('name', '-age'). A hyphen - can be used to prefix a column name to indicate descending order.

Type :tuple
Default :()

Note

This functionality is also available via the order_by keyword argument to a table’s constructor.

sequence

The sequence of the table columns. This allows the default order of columns (the order they were defined in the Table) to be overridden.

Type :any iterable (e.g. tuple or list)
Default :()

The special item "..." can be used as a placeholder that will be replaced with all the columns that weren’t explicitly listed. This allows you to add columns to the front or back when using inheritence.

Example:

>>> class Person(tables.Table):
...     first_name = tables.Column()
...     last_name = tables.Column()
...
...     class Meta:
...         sequence = ("last_name", "...")
...
>>> Person.base_columns.keys()
['last_name', 'first_name']

The "..." item can be used at most once in the sequence value. If it’s not used, every column must be explicitly included. e.g. in the above example, sequence = ("last_name", ) would be invalid because neither "..." or "first_name" were included.

Note

This functionality is also available via the sequence keyword argument to a table’s constructor.

orderable

Default value for column’s orderable attribute.

Type :bool
Default :True

If the Table and Column don’t specify a value, a column’s orderable value will fallback to this. object specify. This provides an easy mechanism to disable ordering on an entire table, without adding orderable=False to each Column in a Table.

Note

This functionality is also available via the orderable keyword argument to a table’s constructor.

template

The default template to use when rendering the table.

Type :unicode
Default :django_tables2/table.html

Note

This functionality is also available via the template keyword argument to a table’s constructor.

TableData Objects:

class django_tables2.tables.TableData(data, table)

Exposes a consistent API for table data.

Parameters:
  • data (QuerySet or list of dict) – iterable containing data for each row
  • tableTable object
order_by(aliases)

Order the data based on order by aliases (prefixed column names) in the table.

Parameters:aliases (OrderByTuple) – optionally prefixed names of columns (‘-‘ indicates descending order) in order of significance with regard to data ordering.
__getitem__(key)

Slicing returns a new TableData instance, indexing returns a single record.

Column Objects:

class django_tables2.columns.Column(verbose_name=None, accessor=None, default=None, visible=True, orderable=None, attrs=None, order_by=None, sortable=None, empty_values=None)

Represents a single column of a table.

Column objects control the way a column (including the cells that fall within it) are rendered.

Parameters:
  • verbose_name (unicode) – A human readable version of the column name. This should not be title case. It is converted to title case for use in column headers.
  • accessor (basestring or Accessor) – An accessor that describes how to extract values for this column from the table data.
  • default

    The default value for the column. This can be a value or a callable object [1]. If an object in the data provides None for a column, the default will be used instead.

    The default value may affect ordering, depending on the type of data the table is using. The only case where ordering is not affected is when a QuerySet is used as the table data (since sorting is performed by the database).

    [1]The provided callable object must not expect to receive any arguments.
  • order_by (unicode, tuple, Accessor) – Allows one or more accessors to be used for ordering rather than accessor.
  • visible (bool) –

    If False, this column will not be in HTML from output generators (e.g. as_html() or {% render_table %}).

    When a field is not visible, it is removed from the table’s columns iterable.

  • orderable (bool) – If False, this column will not be allowed to influence row ordering/sorting.
  • attrs (Attrs object) – HTML attributes to be added to components in the column

Supported Attrs keys are:

  • th<th> element in header
  • td<td> element in body
  • cell – fall back for <th> and <td> should they not be specified

CheckBoxColumn Objects:

class django_tables2.columns.CheckBoxColumn(attrs=None, **extra)

A subclass of Column that renders as a checkbox form input.

This column allows a user to select a set of rows. The selection information can then be used to apply some operation (e.g. “delete”) onto the set of objects that correspond to the selected rows.

The value that is extracted from the table data for this column is used as the value for the checkbox, i.e. <input type="checkbox" value="..." />

This class implements some sensible defaults:

  • HTML input’s name attribute is the column name (can override via attrs argument).
  • orderable defaults to False.

Note

You’d expect that you could select multiple checkboxes in the rendered table and then do something with that. This functionality isn’t implemented. If you want something to actually happen, you’ll need to implement that yourself.

In addition to Attrs keys supported by Column, the following are available:

  • input<input> elements in both <td> and <th>.
  • th__input – If defined: used instead of input in table header.
  • td__input – If defined: used instead of input in table body.

EmailColumn Objects:

class django_tables2.columns.EmailColumn(attrs=None, *args, **kwargs)

A subclass of BaseLinkColumn that renders the cell value as a hyperlink.

It’s common to have a email value in a row hyperlinked to other page.

Parameters:attrs – a dict of HTML attributes that are added to the rendered <a href="...">...</a> tag

Example:

# models.py
class Person(models.Model):
    name = models.CharField(max_length=200)
    email =  models.EmailField()

# tables.py
class PeopleTable(tables.Table):
    name = tables.Column()
    email = tables.EmailColumn()

LinkColumn Objects:

class django_tables2.columns.LinkColumn(viewname, urlconf=None, args=None, kwargs=None, current_app=None, attrs=None, **extra)

Renders a normal value as an internal hyperlink to another page.

It’s common to have the primary value in a row hyperlinked to the page dedicated to that record.

The first arguments are identical to that of django.core.urlresolvers.reverse() and allows an internal URL to be described. The last argument attrs allows custom HTML attributes to be added to the rendered <a href="..."> tag.

Parameters:
  • viewname – See django.core.urlresolvers.reverse().
  • urlconf – See django.core.urlresolvers.reverse().
  • args – See django.core.urlresolvers.reverse(). **
  • kwargs – See django.core.urlresolvers.reverse(). **
  • current_app – See django.core.urlresolvers.reverse().
  • attrs – a dict of HTML attributes that are added to the rendered <input type="checkbox" .../> tag

** In order to create a link to a URL that relies on information in the current row, Accessor objects can be used in the args or kwargs arguments. The accessor will be resolved using the row’s record before reverse() is called.

Example:

# models.py
class Person(models.Model):
    name = models.CharField(max_length=200)

# urls.py
urlpatterns = patterns('',
    url('people/(\d+)/', views.people_detail, name='people_detail')
)

# tables.py
from django_tables2.utils import A  # alias for Accessor

class PeopleTable(tables.Table):
    name = tables.LinkColumn('people_detail', args=[A('pk')])

In addition to Attrs keys supported by Column, the following are available:

  • a<a> elements in <td>.

TemplateColumn Objects:

class django_tables2.columns.TemplateColumn(template_code=None, template_name=None, **extra)

A subclass of Column that renders some template code to use as the cell value.

Parameters:
  • template_code (unicode) – the template code to render
  • template_name (unicode) – the name of the template to render

A django.templates.Template object is created from the template_code or template_name and rendered with a context containing:

  • record – data record for the current row
  • value – value from record that corresponds to the current column
  • default – appropriate default value to use as fallback

Example:

class ExampleTable(tables.Table):
    foo = tables.TemplateColumn('{{ record.bar }}')
    # contents of `myapp/bar_column.html` is `{{ value }}`
    bar = tables.TemplateColumn(template_name='myapp/name2_column.html')

Both columns will have the same output.

Important

In order to use template tags or filters that require a RequestContext, the table must be rendered via {% render_table %}.

URLColumn Objects:

class django_tables2.columns.URLColumn(attrs=None, *args, **kwargs)

A subclass of BaseLinkColumn that renders the cell value as a hyperlink.

It’s common to have a URL value in a row hyperlinked to other page.

Parameters:attrs – a dict of HTML attributes that are added to the rendered <a href="...">...</a> tag

Example:

# models.py
class Person(models.Model):
    name = models.CharField(max_length=200)
    web =  models.URLField()

# tables.py
class PeopleTable(tables.Table):
    name = tables.Column()
    web = tables.URLColumn()

BoundColumns Objects

class django_tables2.columns.BoundColumns(table)

Container for spawning BoundColumn objects.

This is bound to a table and provides its Table.columns property. It provides access to those columns in different ways (iterator, item-based, filtered and unfiltered etc), stuff that would not be possible with a simple iterator in the table class.

A BoundColumns object is a container for holding BoundColumn objects. It provides methods that make accessing columns easier than if they were stored in a list or dict. Columns has a similar API to a dict (it actually uses a SortedDict interally).

At the moment you’ll only come across this class when you access a Table.columns property.

Parameters:table (Table object) – the table containing the columns
__iter__()

Convenience API, alias of itervisible().

__contains__(item)

Check if a column is contained within a Columns object.

item can either be a BoundColumn object, or the name of a column.

__len__()

Return how many BoundColumn objects are contained (and visible).

__getitem__(index)

Retrieve a specific BoundColumn object.

index can either be 0-indexed or the name of a column

columns['speed']  # returns a bound column with name 'speed'
columns[0]        # returns the first column

BoundColumn Objects

class django_tables2.columns.BoundColumn(table, column, name)

A run-time version of Column. The difference between BoundColumn and Column, is that BoundColumn objects include the relationship between a Column and a Table. In practice, this means that a BoundColumn knows the “variable name” given to the Column when it was declared on the Table.

For convenience, all Column properties are available from this class.

Parameters:
  • table (Table object) – the table in which this column exists
  • column (Column object) – the type of column
  • name (basestring object) –

    the variable name of the column used to when defining the Table. In this example the name is age:

    class SimpleTable(tables.Table):
        age = tables.Column()
    
accessor

Returns the string used to access data for this column out of the data source.

attrs

Proxy to Column.attrs but injects some values of our own.

A th and td are guaranteed to be defined (irrespective of what’s actually defined in the column attrs. This makes writing templates easier.

default

Returns the default value for this column.

header

The value that should be used in the header cell for this column.

order_by

Returns an OrderByTuple of appropriately prefixed data source keys used to sort this column.

See order_by_alias() for details.

order_by_alias

Returns an OrderBy describing the current state of ordering for this column.

The following attempts to explain the difference between order_by and order_by_alias.

order_by_alias returns and OrderBy instance that’s based on the name of the column, rather than the keys used to order the table data. Understanding the difference is essential.

Having an alias and a normal version is necessary because an N-tuple (of data source keys) can be used by the column to order the data, and it’s ambiguous when mapping from N-tuple to column (since multiple columns could use the same N-tuple).

The solution is to use order by aliases (which are really just prefixed column names) that describe the ordering state of the column, rather than the specific keys in the data source should be ordered.

e.g.:

>>> class SimpleTable(tables.Table):
...     name = tables.Column(order_by=("firstname", "last_name"))
...
>>> table = SimpleTable([], order_by=("-name", ))
>>> table.columns["name"].order_by_alias
"-name"
>>> table.columns["name"].order_by
("-first_name", "-last_name")

The OrderBy returned has been patched to include an extra attribute next, which returns a version of the alias that would be transitioned to if the user toggles sorting on this column, e.g.:

not sorted -> ascending
ascending  -> descending
descending -> ascending

This is useful otherwise in templates you’d need something like:

{% if column.is_ordered %} {% querystring table.prefixed_order_by_field=column.order_by_alias.opposite %} {% else %} {% querystring table.prefixed_order_by_field=column.order_by_alias %} {% endif %}
orderable

Return a bool depending on whether this column supports ordering.

sortable

deprecated – use orderable instead.

verbose_name

Return the verbose name for this column, or fallback to prettified column name.

If the table is using queryset data, then use the corresponding model field’s verbose_name. If it’s traversing a relationship, then get the last field in the accessor (i.e. stop when the relationship turns from ORM relationships to object attributes [e.g. person.upper should stop at person]).

If the model field’s verbose_name is a SafeData, it’s used unmodified.

visible

Returns a bool depending on whether this column is visible.

BoundRows Objects

class django_tables2.rows.BoundRows(data)

Container for spawning BoundRow objects.

Parameters:data (TableData object) – the table in which the rows exist.

This is used for Table.rows.

BoundRow Objects

class django_tables2.rows.BoundRow(table, record)

Represents a specific row in a table.

BoundRow objects are a container that make it easy to access the final ‘rendered’ values for cells in a row. You can simply iterate over a BoundRow object and it will take care to return values rendered using the correct method (e.g. Column.render_FOO())

To access the rendered value of each cell in a row, just iterate over it:

>>> import django_tables2 as tables
>>> class SimpleTable(tables.Table):
...     a = tables.Column()
...     b = tables.CheckBoxColumn(attrs={'name': 'my_chkbox'})
...
>>> table = SimpleTable([{'a': 1, 'b': 2}])
>>> row = table.rows[0]  # we only have one row, so let's use it
>>> for cell in row:
...     print cell
...
1
<input type="checkbox" name="my_chkbox" value="2" />

Alternatively you can treat it like a list and use indexing to retrieve a specific cell. It should be noted that this will raise an IndexError on failure.

>>> row[0]
1
>>> row[1]
u'<input type="checkbox" name="my_chkbox" value="2" />'
>>> row[2]
...
IndexError: list index out of range

Finally you can also treat it like a dictionary and use column names as the keys. This will raise KeyError on failure (unlike the above indexing using integers).

>>> row['a']
1
>>> row['b']
u'<input type="checkbox" name="my_chkbox" value="2" />'
>>> row['c']
...
KeyError: 'c'
Parameters:
  • table – is the Table in which this row exists.
  • record – a single record from the table data that is used to populate the row. A record could be a Model object, a dict, or something else.
__getitem__(name)

Returns the final rendered value for a cell in the row, given the name of a column.

__contains__(item)

Check by both row object and column name.

__iter__()

Iterate over the rendered values for cells in the row.

Under the hood this method just makes a call to BoundRow.__getitem__() for each cell.

record

The data record from the data source which is used to populate this row with data.

table

The associated Table object.

items()

Returns iterator yielding (bound_column, cell) pairs.

cell is row[name] – the rendered unicode value that should be rendered within ``<td>.

Upgrading from django-tables Version 1

  • Change your INSTALLLED_APPS entry from django_tables.app to django_tables2.

  • Change all your import references from django_tables to django_tables2.

  • Replace all references to the old MemoryTable and ModelTable classes with simply Table.

  • In your templates, load the django_tables2 template library; {% load django_tables2 %} instead of {% load tables %}.

  • A table object is no longer iterable; rather than for row in table, instead you now do explicitly: for row in table.rows.

  • If you were using row.data to access a row’s underlying data, replace it with row.record instead.

  • When declaring columns, replace the use of:

    name_in_dataset = tables.Column(name="wanted_column_name")
    

    with:

    wanted_column_name = tables.Column(accessor="name_in_dataset")
    
  • When declaring columns, replace the use of:

    column_to_override = tables.Column(name="wanted_column_name", data="name_in_dataset")
    

    with:

    wanted_column_name = tables.Column(accessor="name_in_dataset")
    

    and exclude column_to_override via the table meta data.

  • When generating the link to order the column, instead of:

    {% set_url_param sort=column.name_toggled %}
    

    use:

    {% querystring table.order_by_field=column.order_by_alias.next %}
    
  • Replace:

    {{ column.is_ordered_reverse }} and {{ column.is_ordered_straight }}
    

    with:

    {{ column.order_by.is_descending }} and {{ column.order_by.is_ascending }}
    

Glossary

accessor
Refers to an Accessor object
column name

The name given to a column. In the follow example, the column name is age.

class SimpleTable(tables.Table):
    age = tables.Column()
order by alias

A prefixed column name that describes how a column should impact the order of data within the table. This allows the implementation of how a column affects ordering to be abstracted, which is useful (e.g. in querystrings).

class ExampleTable(tables.Table):
    name = tables.Column(order_by=('first_name', 'last_name'))

In this example -name and name are valid order by aliases. In a querystring you might then have ?order=-name.

table
The traditional concept of a table. i.e. a grid of rows and columns containing data.
view
A Django view.
record
A single Python object used as the data for a single row.
render
The act of serialising a Table into HTML.
template
A Django template.
table data
An interable of records that Table uses to populate its rows.