0
# Table Rendering
1
2
Data table rendering with Bootstrap styling, supporting CRUD actions, responsive design, pagination integration, and flexible column formatting options for displaying data collections.
3
4
## Capabilities
5
6
### Complete Table Rendering
7
8
Render data collections as Bootstrap-styled tables with optional CRUD actions and extensive customization.
9
10
```python { .api }
11
def render_table(data, titles=None, primary_key='id', primary_key_title='#',
12
caption=None, table_classes=None, header_classes=None,
13
body_classes=None, responsive=False, responsive_class='table-responsive',
14
safe_columns=None, urlize_columns=None, model=None,
15
show_actions=False, actions_title='Actions', custom_actions=None,
16
view_url=None, edit_url=None, delete_url=None, new_url=None,
17
action_pk_placeholder=':id'):
18
"""
19
Render a data collection as a Bootstrap table.
20
21
Args:
22
data (list): List of objects/dicts to display in table
23
titles (list): List of (field_name, display_title) tuples for columns
24
primary_key (str): Primary key field name (default: 'id')
25
primary_key_title (str): Display title for primary key column (default: '#')
26
caption (str): Table caption text
27
table_classes (str): CSS classes for table element
28
header_classes (str): CSS classes for table header
29
body_classes (str): CSS classes for table body
30
responsive (bool): Enable responsive table wrapper
31
responsive_class (str): CSS class for responsive wrapper
32
safe_columns (list): Column names to render as safe HTML
33
urlize_columns (list): Column names to convert URLs to links
34
model: SQLAlchemy model class for automatic title detection
35
show_actions (bool): Display CRUD action buttons
36
actions_title (str): Title for actions column
37
custom_actions (list): Custom action button definitions
38
view_url (str): URL pattern for view action
39
edit_url (str): URL pattern for edit action
40
delete_url (str): URL pattern for delete action
41
new_url (str): URL for new record creation
42
action_pk_placeholder (str): Placeholder for primary key in URLs
43
44
Returns:
45
Rendered HTML table with Bootstrap styling
46
47
Data Sources:
48
- List of dictionaries
49
- List of SQLAlchemy model instances
50
- List of custom objects with attributes
51
52
URL Patterns:
53
- Use :id placeholder for primary key substitution
54
- Example: '/users/:id/edit' becomes '/users/123/edit'
55
"""
56
```
57
58
### Table Title Generation
59
60
Automatically generate table column titles from SQLAlchemy models.
61
62
```python { .api }
63
def get_table_titles(data, primary_key, primary_key_title):
64
"""
65
Detect and build table titles from SQLAlchemy ORM objects.
66
67
Args:
68
data (list): List of SQLAlchemy model instances
69
primary_key (str): Primary key field name
70
primary_key_title (str): Display title for primary key
71
72
Returns:
73
list: List of (field_name, display_title) tuples
74
75
Behavior:
76
- Extracts column names from SQLAlchemy model metadata
77
- Converts snake_case to Title Case (user_name -> User Name)
78
- Excludes fields starting with underscore
79
- Sets primary key title as specified
80
81
Example:
82
For User model with columns: id, first_name, last_name, email
83
Returns: [('id', '#'), ('first_name', 'First Name'),
84
('last_name', 'Last Name'), ('email', 'Email')]
85
"""
86
```
87
88
### Internal URL Building
89
90
Internal helper for constructing action URLs with dynamic parameters.
91
92
```python { .api }
93
def build_url(record, endpoint, url_tuples, model, pk_field):
94
"""
95
Internal helper to build URLs for table actions.
96
97
Args:
98
record: Data record (dict or object)
99
endpoint (str): Flask endpoint or URL pattern
100
url_tuples (list): URL parameter tuples
101
model: SQLAlchemy model class
102
pk_field (str): Primary key field name
103
104
Returns:
105
str: Constructed URL with substituted parameters
106
107
Note: This is an internal helper used by render_table
108
"""
109
```
110
111
## Table Features
112
113
### Data Source Support
114
115
Bootstrap-Flask tables support multiple data source types:
116
117
#### Dictionary Lists
118
```python
119
data = [
120
{'id': 1, 'name': 'John Doe', 'email': 'john@example.com'},
121
{'id': 2, 'name': 'Jane Smith', 'email': 'jane@example.com'},
122
]
123
```
124
125
#### SQLAlchemy Model Instances
126
```python
127
users = User.query.all() # List of SQLAlchemy model instances
128
```
129
130
#### Custom Objects
131
```python
132
class Person:
133
def __init__(self, id, name, email):
134
self.id = id
135
self.name = name
136
self.email = email
137
138
data = [Person(1, 'John', 'john@example.com')]
139
```
140
141
### Column Configuration
142
143
#### Manual Title Definition
144
```python
145
titles = [
146
('id', '#'),
147
('first_name', 'First Name'),
148
('last_name', 'Last Name'),
149
('email', 'Email Address'),
150
('created_at', 'Date Created')
151
]
152
```
153
154
#### Automatic Title Generation
155
```python
156
# For SQLAlchemy models - automatically generates titles
157
titles = get_table_titles(users, 'id', '#')
158
```
159
160
### CRUD Actions
161
162
Bootstrap-Flask provides built-in CRUD action buttons:
163
164
#### Standard Actions
165
- **View**: Display record details
166
- **Edit**: Modify record
167
- **Delete**: Remove record
168
- **New**: Create new record
169
170
#### Action URL Patterns
171
```python
172
# URL patterns with :id placeholder
173
view_url = '/users/:id'
174
edit_url = '/users/:id/edit'
175
delete_url = '/users/:id/delete'
176
new_url = '/users/new'
177
```
178
179
#### Custom Actions
180
```python
181
custom_actions = [
182
{
183
'title': 'Activate',
184
'url': '/users/:id/activate',
185
'classes': 'btn-success btn-sm'
186
},
187
{
188
'title': 'Archive',
189
'url': '/users/:id/archive',
190
'classes': 'btn-warning btn-sm'
191
}
192
]
193
```
194
195
### Column Formatting
196
197
#### Safe HTML Columns
198
Render column content as safe HTML without escaping:
199
200
```python
201
safe_columns = ['description', 'notes'] # Won't escape HTML tags
202
```
203
204
#### URL Columns
205
Automatically convert URLs to clickable links:
206
207
```python
208
urlize_columns = ['website', 'blog_url'] # Convert to <a> tags
209
```
210
211
### Responsive Design
212
213
Tables can be made responsive to handle overflow on small screens:
214
215
```python
216
# Enable responsive wrapper
217
responsive = True
218
responsive_class = 'table-responsive-md' # Responsive on medium screens and below
219
```
220
221
## Usage Examples
222
223
### Basic Table
224
225
```python
226
# View function
227
@app.route('/users')
228
def users():
229
users = [
230
{'id': 1, 'name': 'John Doe', 'email': 'john@example.com'},
231
{'id': 2, 'name': 'Jane Smith', 'email': 'jane@example.com'},
232
]
233
return render_template('users.html', users=users)
234
```
235
236
```html
237
<!-- Template -->
238
{% from 'base/table.html' import render_table %}
239
240
<div class="container">
241
<h2>Users</h2>
242
{{ render_table(users) }}
243
</div>
244
```
245
246
### Table with Custom Styling
247
248
```html
249
{{ render_table(users,
250
table_classes="table table-striped table-hover table-bordered",
251
header_classes="table-dark",
252
caption="List of registered users"
253
) }}
254
```
255
256
### Table with CRUD Actions
257
258
```html
259
{{ render_table(users,
260
show_actions=True,
261
view_url="/users/:id",
262
edit_url="/users/:id/edit",
263
delete_url="/users/:id/delete",
264
new_url="/users/new",
265
actions_title="Operations"
266
) }}
267
```
268
269
### SQLAlchemy Model Table
270
271
```python
272
# Model
273
class User(db.Model):
274
id = db.Column(db.Integer, primary_key=True)
275
first_name = db.Column(db.String(50))
276
last_name = db.Column(db.String(50))
277
email = db.Column(db.String(120))
278
created_at = db.Column(db.DateTime)
279
280
# View
281
@app.route('/users')
282
def users():
283
users = User.query.all()
284
titles = get_table_titles(users, 'id', 'User ID')
285
return render_template('users.html', users=users, titles=titles)
286
```
287
288
```html
289
{{ render_table(users, titles=titles, model=User, show_actions=True) }}
290
```
291
292
### Responsive Table with Custom Columns
293
294
```html
295
{{ render_table(products,
296
titles=[
297
('id', 'ID'),
298
('name', 'Product Name'),
299
('description', 'Description'),
300
('price', 'Price'),
301
('website', 'Website')
302
],
303
responsive=True,
304
responsive_class="table-responsive-lg",
305
safe_columns=['description'],
306
urlize_columns=['website'],
307
table_classes="table table-sm"
308
) }}
309
```
310
311
### Table with Custom Actions
312
313
```html
314
{{ render_table(orders,
315
show_actions=True,
316
custom_actions=[
317
{
318
'title': 'Ship',
319
'url': '/orders/:id/ship',
320
'classes': 'btn-success btn-sm'
321
},
322
{
323
'title': 'Cancel',
324
'url': '/orders/:id/cancel',
325
'classes': 'btn-danger btn-sm'
326
},
327
{
328
'title': 'Invoice',
329
'url': '/orders/:id/invoice',
330
'classes': 'btn-info btn-sm'
331
}
332
]
333
) }}
334
```
335
336
### Table with Pagination Integration
337
338
```python
339
# View with pagination
340
@app.route('/users')
341
def users():
342
page = request.args.get('page', 1, type=int)
343
users = User.query.paginate(
344
page=page, per_page=10, error_out=False
345
)
346
return render_template('users.html', users=users)
347
```
348
349
```html
350
{% from 'base/table.html' import render_table %}
351
{% from 'base/pagination.html' import render_pagination %}
352
353
{{ render_table(users.items, show_actions=True) }}
354
{{ render_pagination(users) }}
355
```
356
357
### Advanced Configuration
358
359
```html
360
{{ render_table(data,
361
titles=custom_titles,
362
primary_key='user_id',
363
primary_key_title='User ID',
364
table_classes="table table-striped table-hover",
365
header_classes="table-primary",
366
body_classes="small",
367
responsive=True,
368
responsive_class="table-responsive-md",
369
safe_columns=['bio', 'notes'],
370
urlize_columns=['website', 'linkedin'],
371
show_actions=True,
372
actions_title="Manage",
373
view_url="/users/:id/profile",
374
edit_url="/users/:id/settings",
375
delete_url="/admin/users/:id/delete",
376
new_url="/users/register",
377
action_pk_placeholder=':id'
378
) }}
379
```
380
381
### Empty Table Handling
382
383
```html
384
{% if data %}
385
{{ render_table(data) }}
386
{% else %}
387
<div class="alert alert-info">
388
<h4>No Records Found</h4>
389
<p>There are currently no records to display.</p>
390
<a href="{{ url_for('new_record') }}" class="btn btn-primary">
391
Add New Record
392
</a>
393
</div>
394
{% endif %}
395
```
396
397
## Configuration Variables
398
399
Table rendering respects several Flask configuration variables:
400
401
```python
402
# Table action button titles (configurable)
403
app.config['BOOTSTRAP_TABLE_VIEW_TITLE'] = 'View'
404
app.config['BOOTSTRAP_TABLE_EDIT_TITLE'] = 'Edit'
405
app.config['BOOTSTRAP_TABLE_DELETE_TITLE'] = 'Delete'
406
app.config['BOOTSTRAP_TABLE_NEW_TITLE'] = 'New'
407
```
408
409
These configuration values are used as default titles for CRUD action buttons and can be overridden at the template level.