Basic usage
Here you can find complete usage instructions for the Tables extension. The process is fairly simple and involves only several steps:
- Defining a table
- Creating a view to display the table
We're going to use a demo table definition called PeopleTable for demonstration purposes.
It's a working example located in a separate extension and can be enabled alongside the tables extension. Just add tables_demo to your ckan.plugins configuration.
The demo table uses all the features of the tables extension, including data sources, formatters, all action types, and exporters. A minimal example could be much simpler, but this one demonstrates the full power of the extension.
Defining a Table
First, create a table definition by inheriting from TableDefinition.
We will use the ListDataSource with a mock data for demonstration purposes, but in a real-world scenario, you might want to use DatabaseDataSource or create a custom data source. Read more about data sources here.
In general, ListDataSource is suitable for small datasets or testing, while DatabaseDataSource is recommended for production use with larger datasets.
If you're interested in how we're generating the mock data, check out the generate_mock_data function below:
Source code in ckanext/tables_demo/utils.py
4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Below is the full code of the PeopleTable definition:
import ckanext.tables.shared as t
from ckanext.tables_demo.utils import generate_mock_data
DATA = generate_mock_data(1000)
class PeopleTable(t.TableDefinition):
"""Demo table definition for the people table."""
def __init__(self):
super().__init__(
name="people",
data_source=t.ListDataSource(data=DATA),
columns=[
t.ColumnDefinition(field="id", width=70),
t.ColumnDefinition(field="name"),
t.ColumnDefinition(field="surname", title="Last Name"),
t.ColumnDefinition(field="email"),
t.ColumnDefinition(
field="created",
formatters=[
(t.formatters.DateFormatter, {"date_format": "%d %B %Y"})
],
),
],
row_actions=[
t.RowActionDefinition(
action="remove_user",
label="Remove User",
icon="fa fa-trash",
callback=self.remove_user,
with_confirmation=True,
),
],
bulk_actions=[
t.BulkActionDefinition(
action="remove_user",
label="Remove Selected Users",
icon="fa fa-trash",
callback=self.remove_users,
),
],
table_actions=[
t.TableActionDefinition(
action="remove_all_users",
label="Remove All Users",
icon="fa fa-trash",
callback=self.remove_all_users,
),
t.TableActionDefinition(
action="recreate_users",
label="Recreate Users",
icon="fa fa-refresh",
callback=self.recreate_users,
),
],
exporters=t.ALL_EXPORTERS,
)
def remove_user(self, row: t.Row) -> t.ActionHandlerResult:
"""Callback to remove a user from the data source."""
DATA[:] = [r for r in DATA if r["id"] != row["id"]]
return t.ActionHandlerResult(success=True, message="User removed.")
def remove_users(self, rows: list[t.Row]) -> t.ActionHandlerResult:
"""Callback to remove a user from the data source."""
ids_to_remove = {row["id"] for row in rows}
DATA[:] = [r for r in DATA if r["id"] not in ids_to_remove]
return t.ActionHandlerResult(success=True, message="Users removed.")
def remove_all_users(self) -> t.ActionHandlerResult:
"""Callback to remove all users from the data source."""
DATA.clear()
return t.ActionHandlerResult(success=True, message="All users removed.")
def recreate_users(self) -> t.ActionHandlerResult:
"""Callback to recreate the mock users."""
DATA[:] = generate_mock_data(1000)
return t.ActionHandlerResult(success=True, message="Users recreated.")
Using Formatters
The tables extension provides several built-in formatters to change the way data is rendered in the table cells. You can apply one or more formatters to a column by specifying them in the formatters attribute of ColumnDefinition.
For example, from the above PeopleTable, we are using the datetime formatter to format the created field. So this 2024-02-25T11:10:00Z value will be displayed as 2024-02-25.
ColumnDefinition(
field="created",
formatters=[(formatters.DateFormatter, {"date_format": "%Y-%m-%d"})],
sortable=True
),
Using Exporters
The tables extension also provides several built-in exporters to export the table data in different formats. You can specify the exporters to be used in the exporters attribute of the TableDefinition.
In the above PeopleTable, we are using all the available exporters by specifying t.ALL_EXPORTERS. You can also specify individual exporters if you want to limit the available export options.
exporters=[
t.exporters.CSVExporter,
t.exporters.TSVExporter,
],
Obviously, you can write your own custom exporters as well. See the exporters documentation for more information.
Using Actions
The tables extension allows you to define actions that can be performed on individual rows or on multiple selected rows. You can define these actions in the row_actions, table_actions and bulk_actions attributes of the TableDefinition.
Basically, it's just a matter of defining the action and providing a callback function that will be called when the action is triggered.
Read more about actions in the actions documentation.
Creating a View
Once your table is defined, you can create a view to display it using the GenericTableView:
from flask import Blueprint
from ckanext.tables.shared import GenericTableView
from ckanext.tables_demo.table import PeopleTable
bp = Blueprint("tables_demo", __name__, url_prefix="/tables-demo")
bp.add_url_rule("/people", view_func=GenericTableView.as_view("people", table=PeopleTable))
As you can see, this view does not require any custom code to render the table. The GenericTableView takes care of everything.
Results
After completing the above steps, you can navigate to /admin/people in your CKAN instance to see the rendered table.

Next Steps
- Learn about Data Sources for different data backends
- Explore Built-In and Custom Formatters to enhance table presentation.
- Explore Actions to add interactivity to your tables.
- Explore Exporters to provide data export functionality.