Tables
======
iommi tables makes it easy to create full featured HTML tables easily:
* generates header, rows and cells
* sorting
* filtering
* pagination
* bulk edit
* link creation
* customization on multiple levels, all the way down to templates for cells
* automatic rowspan
* grouping of headers
.. image:: tables_example_albums.png
The code for the example above:
.. code-block:: python
Table(
auto__model=Album,
page_size=10,
)
Read the full documentation and the :doc:`cookbook` for more.
Creating tables from models
---------------------------
Say I have some model:
.. code-block:: python
class Foo(models.Model):
a = models.IntegerField()
def __str__(self):
return f'Foo: {self.a}'
.. code-block:: python
class Bar(models.Model):
b = models.ForeignKey(Foo, on_delete=models.CASCADE)
c = models.CharField(max_length=255)
Now I can display a list of `Bar` in a table like this:
.. code-block:: python
def my_view(request):
return Table(auto__model=Bar)
This automatically creates a table with pagination and sorting. If you pass
`query_from_indexes=True` you will get filters for all the model fields
that have database indexes. This filtering system includes an advanced filter
language. See :doc:`queries` for more on filtering.
Explicit tables
---------------
You can also create tables explicitly:
.. code-block:: python
def albums(request):
class AlbumTable(Table):
# Shortcut for creating checkboxes to select rows
select = Column.select()
name = Column()
# Show the name field from Artist. This works for plain old objects too.
artist_name = Column(
attr='artist__name',
# put this field into the query language
filter__include=True,
)
year = Column.number(
# Enable bulk editing for this field
bulk__include=True,
)
return AlbumTable(rows=Album.objects.all())
This gives me a view with filtering, sorting, bulk edit and pagination.
.. raw:: html
▼ Hide result
Table as CSV
------------
Tables are able to render as CSV files. This is enabled if there is specified a name to use on the resulting file,
as a value of the table parameter `extra_evaluated__report_name`, and a file header name for each column that is
to be included, specified by the column parameter `extra_evaluated__report_name`.
For example:
.. code-block:: python
def albums(request):
class AlbumTable(Table):
class Meta:
extra_evaluated__report_name = 'Albums'
actions__download = Action(
attrs__href=lambda table, **_: '?' + table.endpoints.csv.endpoint_path,
)
name = Column(extra_evaluated__report_name='Name')
artist = Column(extra_evaluated__report_name='Artist')
year = Column.number(extra_evaluated__report_name='Artist')
return AlbumTable(rows=Album.objects.all())
This will behave like an ordinary table but when the csv rendering endpoint is invoked the content will be
returned as a text file in CSV format.
.. raw:: html
▼ Hide result
You can also pass kwargs to the `csv.writer` such as `delimiter`, `quotechar`, etc.
with `extra_evaluated__csv_writer_kwargs = {'delimiter': ';', ...}`.
Table of plain python objects
-----------------------------
.. code-block:: python
def plain_objs_view(request):
# Say I have a class...
class Foo(object):
def __init__(self, i):
self.a = i
self.b = 'foo %s' % (i % 3)
self.c = (i, 1, 2, 3, 4)
# and a list of them
foos = [Foo(i) for i in range(4)]
# I can declare a table:
class FooTable(Table):
a = Column.number()
b = Column()
# Display the last value of the tuple
c = Column(
cell__format=lambda value, **_: value[-1],
)
# Calculate a value not present in Foo
sum_c = Column(
cell__value=lambda row, **_: sum(row.c),
sortable=False,
)
# now to get an HTML table:
return FooTable(rows=foos)
.. raw:: html
▼ Hide result
All these examples and a bigger example using many more features can be found in the examples project.