Skip to content

Exporters

The tables extension 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.

Each exporter is a class that inherits from BaseExporter and implements the export method.

To use an exporter, you need to import the desired exporter from ckanext.tables.shared and add it to the exporters list in the TableDefinition.

import ckanext.tables.shared as t

class MyTable(t.TableDefinition):
    def __init__(self):
        super().__init__(
            ...
            exporters=[
                t.exporters.CSVExporter,
                t.exporters.TSVExporter,
            ]
        )

Below you can see the source code for the base exporter class.

ExporterBase

Base class for table data exporters.

Source code in ckanext/tables/exporters.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class ExporterBase:
    """Base class for table data exporters."""

    name: str
    label: str
    mime_type: str

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        """Export the table data.

        Args:
            table: The table definition.
            params: The query parameters.

        Returns:
            The exported data as bytes.
        """
        raise NotImplementedError

    @classmethod
    def get_table_columns(cls, table: "TableDefinition") -> list["ColumnDefinition"]:
        """Get the list of table columns to be exported.

        Returns:
            A list of column field names.
        """
        # avoid circular import
        from ckanext.tables.table import COLUMN_ACTIONS_FIELD  # noqa PLC0415

        return [col for col in table.columns if col.field != COLUMN_ACTIONS_FIELD]

List of Built-in Exporters

Below is a list of the available built-in exporters along with a brief description of each.

CSV Exporter

CSV exporter for table data.

Source code in ckanext/tables/exporters.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class CSVExporter(ExporterBase):
    """CSV exporter for table data."""

    name = "csv"
    label = tk._("CSV")
    mime_type = "text/csv"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        output = StringIO()
        writer = csv.writer(output)
        columns = cls.get_table_columns(table)

        header = [col.title for col in columns]
        writer.writerow(header)

        # Write data rows
        data = table.get_raw_data(params, paginate=False)

        for row in data:
            writer.writerow([row.get(col.field, "") for col in columns])

        return output.getvalue().encode("utf-8")

TSV Exporter

TSV exporter for table data.

Source code in ckanext/tables/exporters.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class TSVExporter(ExporterBase):
    """TSV exporter for table data."""

    name = "tsv"
    label = tk._("TSV")
    mime_type = "text/tab-separated-values"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        output = StringIO()
        writer = csv.writer(output, delimiter="\t")

        columns = cls.get_table_columns(table)
        header = [col.title for col in columns]
        writer.writerow(header)

        # Rows
        data = table.get_raw_data(params, paginate=False)
        for row in data:
            writer.writerow([row.get(col.field, "") for col in columns])

        return output.getvalue().encode("utf-8")

JSON Exporter

JSON exporter for table data.

Source code in ckanext/tables/exporters.py
76
77
78
79
80
81
82
83
84
85
86
87
class JSONExporter(ExporterBase):
    """JSON exporter for table data."""

    name = "json"
    label = tk._("JSON")
    mime_type = "application/json"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        data = table.get_raw_data(params, paginate=False)

        return json.dumps(data, default=str).encode("utf-8")

XLSX Exporter

Excel (XLSX) exporter for table data.

Source code in ckanext/tables/exporters.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class XLSXExporter(ExporterBase):
    """Excel (XLSX) exporter for table data."""

    name = "xlsx"
    label = tk._("Excel")
    mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        try:
            from openpyxl import Workbook  # noqa: PLC0415
        except ImportError:
            log.warning("openpyxl is required for XLSX export but is not installed.")
            return b""

        wb = Workbook()
        ws = wb.active
        ws.title = "Data"  # type: ignore

        columns = cls.get_table_columns(table)
        header = [col.title for col in columns]
        ws.append(header)  # type: ignore

        # Write data rows
        data = table.get_raw_data(params, paginate=False)
        for row in data:
            ws.append([row.get(col.field, "") for col in columns])  # type: ignore

        output = BytesIO()
        wb.save(output)
        return output.getvalue()

HTML Exporter

HTML exporter for table data.

Source code in ckanext/tables/exporters.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
class HTMLExporter(ExporterBase):
    """HTML exporter for table data."""

    name = "html"
    label = tk._("HTML")
    mime_type = "text/html"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        data = table.get_raw_data(params, paginate=False)
        columns = cls.get_table_columns(table)
        headers = [col.title for col in columns]

        rows_html = "\n".join(
            "<tr>{}</tr>".format("".join("<td>{}</td>".format(row.get(col.field, "")) for col in columns))
            for row in data
        )
        thead = "<tr>{}</tr>".format("".join(f"<th>{h}</th>" for h in headers))
        html = f"""
        <html>
            <head><meta charset="utf-8"><title>{table.name}</title></head>
            <body>
                <table border="1">
                    <thead>{thead}</thead>
                    <tbody>{rows_html}</tbody>
                </table>
            </body>
        </html>
        """
        return html.encode("utf-8")

YAML Exporter

YAML exporter for table data.

Source code in ckanext/tables/exporters.py
147
148
149
150
151
152
153
154
155
156
157
class YAMLExporter(ExporterBase):
    """YAML exporter for table data."""

    name = "yaml"
    label = tk._("YAML")
    mime_type = "application/x-yaml"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        data = table.get_raw_data(params, paginate=False)
        return yaml.safe_dump(data, allow_unicode=True).encode("utf-8")

NDJSON Exporter

NDJSON exporter for table data.

Source code in ckanext/tables/exporters.py
160
161
162
163
164
165
166
167
168
169
170
171
class NDJSONExporter(ExporterBase):
    """NDJSON exporter for table data."""

    name = "ndjson"
    label = tk._("NDJSON")
    mime_type = "application/x-ndjson"

    @classmethod
    def export(cls, table: "TableDefinition", params: "QueryParams") -> bytes:
        data = table.get_raw_data(params, paginate=False)
        lines = [json.dumps(row, default=str) for row in data]
        return "\n".join(lines).encode("utf-8")