Skip to content

Column Renderers

We're using column renderers to display the data in a more user-friendly way using the ckanext-collection. The extension provides a few built-in renderers, but you can also create your own custom renderers and register it with an interface provided by the extension. See the interface documentation for more information.

See the example below, where we're using the date renderer to display the date in a more readable format, and a user_link renderer that recieves a user ID and returns a link to the user profile page with a placeholder avatar.

1733225927595

In-built renderers

bool(value, options, name, record, self)

Render a boolean value as a string.

PARAMETER DESCRIPTION
value

boolean value

TYPE: Any

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

RETURNS DESCRIPTION
str

"Yes" if value is True, otherwise "No"

Source code in ckanext/ap_main/col_renderers.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
@renderer
def bool(
    value: Any, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Render a boolean value as a string.

    Args:
        value (Any): boolean value
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Returns:
        "Yes" if value is True, otherwise "No"
    """
    return "Yes" if value else "No"

date(value, options, name, record, self)

Render a datetime object as a string.

PARAMETER DESCRIPTION
value

date value

TYPE: datetime

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

Options
  • date_format (str) - date format string. Default is %d/%m/%Y - %H:%M
RETURNS DESCRIPTION
str

formatted date

Source code in ckanext/ap_main/col_renderers.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@renderer
def date(
    value: datetime, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Render a datetime object as a string.

    Args:
        value (datetime): date value
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Options:
        - `date_format` (str) - date format string. **Default** is `%d/%m/%Y - %H:%M`

    Returns:
        formatted date
    """
    date_format: str = options.get("date_format", "%d/%m/%Y - %H:%M")

    return tk.h.render_datetime(value, date_format=date_format)

day_passed(value, options, name, record, self)

Calculate the number of days passed since the date.

PARAMETER DESCRIPTION
value

date value

TYPE: Any

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

RETURNS DESCRIPTION
str

A priority badge with day counter and color based on priority.

Source code in ckanext/ap_main/col_renderers.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
@renderer
def day_passed(
    value: Any, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Calculate the number of days passed since the date.

    Args:
        value (Any): date value
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Returns:
        A priority badge with day counter and color based on priority.
    """
    if not value:
        return "0"

    try:
        datetime_obj = datetime.fromisoformat(value)
    except AttributeError:
        return "0"

    current_date = datetime.now()

    days_passed = (current_date - datetime_obj).days

    return tk.literal(
        tk.render(
            "admin_panel/renderers/day_passed.html",
            extra_vars={"value": days_passed},
        )
    )

list(value, options, name, record, self)

Render a list as a comma-separated string.

PARAMETER DESCRIPTION
value

list value

TYPE: Any

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

RETURNS DESCRIPTION
str

comma-separated string

Source code in ckanext/ap_main/col_renderers.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
@renderer
def list(
    value: Any, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Render a list as a comma-separated string.

    Args:
        value (Any): list value
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Returns:
        comma-separated string
    """
    return ", ".join(value)

log_level(value, options, name, record, self)

Render a log level as a string.

PARAMETER DESCRIPTION
value

numeric representation of logging level

TYPE: Any

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

RETURNS DESCRIPTION
str

log level name

Source code in ckanext/ap_main/col_renderers.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@renderer
def log_level(
    value: int, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Render a log level as a string.

    Args:
        value (Any): numeric representation of logging level
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Returns:
        log level name
    """
    return logging.getLevelName(value)

trim_string(value, options, name, record, self)

Trim string to a certain length.

PARAMETER DESCRIPTION
value

string value

TYPE: str

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

Options
  • max_length (int) - maximum length of the string. Default is 79
  • add_ellipsis (bool) - add ellipsis to the end of the string. Default is True
RETURNS DESCRIPTION
str

trimmed string

Source code in ckanext/ap_main/col_renderers.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
@renderer
def trim_string(
    value: str, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Trim string to a certain length.

    Args:
        value (str): string value
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Options:
        - `max_length` (int) - maximum length of the string. **Default** is `79`
        - `add_ellipsis` (bool) - add ellipsis to the end of the string. **Default** is `True`

    Returns:
        trimmed string
    """
    if not value:
        return ""

    max_length: int = options.get("max_length", 79)
    trimmed_value: str = value[:max_length]

    if tk.asbool(options.get("add_ellipsis", True)):
        trimmed_value += "..."

    return trimmed_value

Generate a link to the user profile page with an avatar.

It's a custom implementation of the linked_user function, where we replace an actual user avatar with a placeholder.

Fetching an avatar requires an additional user_show call, and it's too expensive to do it for every user in the list. So we use a placeholder

PARAMETER DESCRIPTION
value

user ID

TYPE: str

options

options for the renderer

TYPE: dict[str, Any]

name

column name

TYPE: str

record

row data

TYPE: Any

self

serializer instance

TYPE: BaseSerializer

Options
  • maxlength (int) - maximum length of the user name. Default is 20
  • avatar (int) - size of the avatar. Default is 20
RETURNS DESCRIPTION
str

User link with an avatar placeholder

Source code in ckanext/ap_main/col_renderers.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
@renderer
def user_link(
    value: str, options: dict[str, Any], name: str, record: Any, self: BaseSerializer
) -> str:
    """Generate a link to the user profile page with an avatar.

    It's a custom implementation of the linked_user
    function, where we replace an actual user avatar with a placeholder.

    Fetching an avatar requires an additional user_show call, and it's too
    expensive to do it for every user in the list. So we use a placeholder

    Args:
        value (str): user ID
        options (dict[str, Any]): options for the renderer
        name (str): column name
        record (Any): row data
        self (BaseSerializer): serializer instance

    Options:
        - `maxlength` (int) - maximum length of the user name. **Default** is `20`
        - `avatar` (int) - size of the avatar. **Default** is `20`

    Returns:
        User link with an avatar placeholder
    """
    if not value:
        return ""

    user = model.User.get(value)

    if not user:
        return value

    maxlength = options.get("maxlength") or 20
    avatar = options.get("maxlength") or 20

    display_name = user.display_name

    if maxlength and len(user.display_name) > maxlength:
        display_name = display_name[:maxlength] + "..."

    return tk.h.literal(
        "{icon} {link}".format(
            icon=tk.h.snippet(
                "user/snippets/placeholder.html", size=avatar, user_name=display_name
            ),
            link=tk.h.link_to(display_name, tk.h.url_for("user.read", id=user.name)),
        )
    )