Skip to content

ListDataSource

The ListDataSource works with Python lists of dictionaries. It's useful for testing, demos, or when working with pre-loaded data.

Basic Usage

from ckanext.tables.shared import ListDataSource

# Sample data
users_data = [
    {"id": 1, "name": "alice", "email": "alice@example.com", "age": 30},
    {"id": 2, "name": "bob", "email": "bob@example.com", "age": 25},
    {"id": 3, "name": "charlie", "email": "charlie@example.com", "age": 35},
]

data_source = ListDataSource(users_data)

Definition

A data source that uses a list of dictionaries as the data source.

This is useful for testing and demo purposes, when you already have data on your hand.

PARAMETER DESCRIPTION
data

The list of dictionaries to use as the data source

TYPE: list[dict[str, Any]]

Source code in ckanext/tables/data_sources.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
class ListDataSource(BaseDataSource):
    """A data source that uses a list of dictionaries as the data source.

    This is useful for testing and demo purposes, when you already have data
    on your hand.

    Args:
        data: The list of dictionaries to use as the data source

    """

    def __init__(self, data: list[dict[str, Any]]):
        self.data = data
        self.filtered = data

    def filter(
        self, field: str | None, operator: str | None, value: str | None
    ) -> Self:
        self.filtered = self.data

        if field and operator and value:
            pred = self.build_filter(field, operator, value)
            if pred:
                self.filtered = [row for row in self.filtered if pred(row)]
        return self

    def build_filter(
        self, field: str, operator: str, value: str
    ) -> Callable[[dict[str, Any]], bool] | None:
        operators: dict[str, Callable[[str, str], bool]] = {
            "=": lambda a, b: a == b,
            "!=": lambda a, b: a != b,
            "<": lambda a, b: a < b,
            "<=": lambda a, b: a <= b,
            ">": lambda a, b: a > b,
            ">=": lambda a, b: a >= b,
            "like": lambda a, b: b.lower() in a.lower(),
        }

        if op_func := operators.get(operator):
            return lambda row: op_func(str(row.get(field, "")), str(value))

        return None

    def sort(self, sort_by: str | None, sort_order: str | None) -> Self:
        if not sort_by:
            return self

        self.filtered = sorted(
            self.filtered,
            key=lambda x: x.get(sort_by),
            reverse=(sort_order or "").lower() == "desc",
        )

        return self

    def paginate(self, page: int, size: int) -> Self:
        if page and size:
            start = (page - 1) * size
            end = start + size
            self.filtered = self.filtered[start:end]
        return self

    def all(self):
        return self.filtered

    def count(self):
        return len(self.filtered)

Best Practices

  • Suitable for small amout of data
  • Consider caching expensive data preparation