0
# Helper Functions and Utilities
1
2
Utility functions and classes for form handling, URL generation, security validation, template context management, and various administrative interface support functions.
3
4
## Capabilities
5
6
### View Management Functions
7
8
Functions for managing current view context and URL generation within Flask-Admin.
9
10
```python { .api }
11
def set_current_view(view):
12
"""
13
Set current administrative view in request context.
14
15
Args:
16
view (BaseView): Admin view to set as current
17
"""
18
19
def get_current_view():
20
"""
21
Get current administrative view from request context.
22
23
Returns:
24
BaseView: Current admin view or None
25
"""
26
27
def get_url(endpoint, **kwargs):
28
"""
29
Generate URL for endpoint with admin context.
30
Alternative to Flask url_for with admin-specific functionality.
31
32
Args:
33
endpoint (str): Endpoint name
34
**kwargs: URL parameters
35
36
Returns:
37
str: Generated URL
38
"""
39
```
40
41
### Form Utilities
42
43
Helper functions for form validation, data handling, and error management.
44
45
```python { .api }
46
def is_required_form_field(field):
47
"""
48
Check if form field has required validators.
49
50
Args:
51
field: WTForms field instance
52
53
Returns:
54
bool: True if field is required
55
"""
56
57
def is_form_submitted():
58
"""
59
Check if current request contains form submission.
60
61
Returns:
62
bool: True if request method is POST or PUT
63
"""
64
65
def validate_form_on_submit(form):
66
"""
67
Validate form if it has been submitted.
68
69
Args:
70
form: WTForms form instance
71
72
Returns:
73
bool: True if form is submitted and valid
74
"""
75
76
def get_form_data():
77
"""
78
Get form data from current request.
79
80
Returns:
81
dict: Form data from request
82
"""
83
84
def is_field_error(errors):
85
"""
86
Check if field has validation errors.
87
88
Args:
89
errors: Field errors list
90
91
Returns:
92
bool: True if field has errors
93
"""
94
95
def flash_errors(form, message):
96
"""
97
Flash form validation errors to user.
98
99
Args:
100
form: Form instance with errors
101
message (str): Base error message
102
"""
103
```
104
105
### Template Context Functions
106
107
Functions for managing template context and Jinja2 integration.
108
109
```python { .api }
110
def resolve_ctx(context):
111
"""
112
Resolve Jinja2 template context.
113
114
Args:
115
context: Jinja2 context object
116
117
Returns:
118
dict: Resolved context dictionary
119
"""
120
121
def get_render_ctx():
122
"""
123
Get current view template context.
124
125
Returns:
126
dict: Template context variables
127
"""
128
```
129
130
### Utility Functions
131
132
General utility functions for string processing, class name handling, and security.
133
134
```python { .api }
135
def prettify_class_name(name):
136
"""
137
Convert PascalCase class name to readable text.
138
139
Args:
140
name (str): Class name in PascalCase
141
142
Returns:
143
str: Human-readable name
144
"""
145
146
def is_safe_url(target):
147
"""
148
Validate URL safety for redirects.
149
150
Args:
151
target (str): URL to validate
152
153
Returns:
154
bool: True if URL is safe for redirecting
155
"""
156
157
def get_redirect_target(param_name='url'):
158
"""
159
Get safe redirect target from request parameters.
160
161
Args:
162
param_name (str): Parameter name containing redirect URL
163
164
Returns:
165
str: Safe redirect URL or None
166
"""
167
```
168
169
### Import and Module Utilities
170
171
Dynamic import utilities for loading modules and attributes by name.
172
173
```python { .api }
174
def import_module(name, required=True):
175
"""
176
Dynamically import module by name.
177
178
Args:
179
name (str): Module name to import
180
required (bool): Raise exception if import fails
181
182
Returns:
183
module: Imported module or None if not required
184
"""
185
186
def import_attribute(name):
187
"""
188
Import attribute by string reference (e.g., 'module.Class').
189
190
Args:
191
name (str): Fully qualified attribute name
192
193
Returns:
194
object: Imported attribute
195
"""
196
197
def module_not_found(additional_depth=0):
198
"""
199
Check if ImportError originated from missing module.
200
201
Args:
202
additional_depth (int): Additional stack frames to check
203
204
Returns:
205
bool: True if error is from missing module
206
"""
207
```
208
209
### Object Utilities
210
211
Functions for accessing object attributes with advanced features.
212
213
```python { .api }
214
def rec_getattr(obj, attr, default=None):
215
"""
216
Recursive getattr with dot notation support.
217
218
Args:
219
obj: Object to get attribute from
220
attr (str): Attribute name with optional dot notation (e.g., 'user.profile.name')
221
default: Default value if attribute not found
222
223
Returns:
224
object: Attribute value or default
225
"""
226
227
def get_dict_attr(obj, attr, default=None):
228
"""
229
Get attribute without triggering __getattr__ magic method.
230
231
Args:
232
obj: Object to get attribute from
233
attr (str): Attribute name
234
default: Default value if attribute not found
235
236
Returns:
237
object: Attribute value or default
238
"""
239
```
240
241
### Encoding Utilities
242
243
Functions for encoding and decoding data for URL parameters and storage.
244
245
```python { .api }
246
def escape(value):
247
"""
248
Escape special characters for safe URL encoding.
249
250
Args:
251
value (str): String to escape
252
253
Returns:
254
str: Escaped string
255
"""
256
257
def iterencode(iter):
258
"""
259
Encode enumerable (list/tuple) as string for URL parameters.
260
261
Args:
262
iter: Iterable to encode
263
264
Returns:
265
str: Encoded string representation
266
"""
267
268
def iterdecode(value):
269
"""
270
Decode string back to tuple/list from iterencode.
271
272
Args:
273
value (str): Encoded string
274
275
Returns:
276
tuple: Decoded values
277
"""
278
```
279
280
### Internationalization Functions
281
282
Translation and localization support functions.
283
284
```python { .api }
285
def gettext(string, **variables):
286
"""
287
Get translated string with variable substitution.
288
289
Args:
290
string (str): String to translate
291
**variables: Variables for string formatting
292
293
Returns:
294
str: Translated string
295
"""
296
297
def ngettext(singular, plural, num, **variables):
298
"""
299
Get pluralized translation based on number.
300
301
Args:
302
singular (str): Singular form
303
plural (str): Plural form
304
num (int): Number for pluralization
305
**variables: Variables for string formatting
306
307
Returns:
308
str: Translated string (singular or plural)
309
"""
310
311
def lazy_gettext(string, **variables):
312
"""
313
Lazy translation that resolves when string is used.
314
315
Args:
316
string (str): String to translate
317
**variables: Variables for string formatting
318
319
Returns:
320
LazyString: Lazy translation object
321
"""
322
```
323
324
## Constants
325
326
URL and encoding constants used throughout Flask-Admin.
327
328
```python { .api }
329
VALID_SCHEMES = ['http', 'https'] # Valid URL schemes for safety checking
330
CHAR_ESCAPE = '.' # Character used for escaping
331
CHAR_SEPARATOR = ',' # Character used for separating values
332
```
333
334
## Usage Examples
335
336
### Custom Form Validation Helper
337
338
```python
339
from flask_admin.helpers import validate_form_on_submit, flash_errors
340
from flask import request, flash, redirect, url_for
341
342
class CustomModelView(ModelView):
343
def create_view(self):
344
form = self.create_form()
345
346
if validate_form_on_submit(form):
347
try:
348
if self.create_model(form):
349
flash('Record created successfully!', 'success')
350
return redirect(url_for('.index_view'))
351
else:
352
flash('Failed to create record.', 'error')
353
except Exception as ex:
354
flash(f'Error: {str(ex)}', 'error')
355
else:
356
# Flash form validation errors
357
if request.method == 'POST':
358
flash_errors(form, 'Please correct the errors below:')
359
360
return self.render('admin/model/create.html', form=form)
361
```
362
363
### Safe URL Redirection
364
365
```python
366
from flask_admin.helpers import is_safe_url, get_redirect_target
367
from flask import request, redirect, url_for
368
369
class SecureView(BaseView):
370
@expose('/')
371
def index(self):
372
# Get safe redirect target
373
next_url = get_redirect_target('next')
374
375
if next_url and is_safe_url(next_url):
376
return redirect(next_url)
377
378
return self.render('admin/secure_index.html')
379
380
@expose('/login')
381
def login(self):
382
# Validate redirect URL from query parameter
383
next_url = request.args.get('next')
384
385
if next_url and not is_safe_url(next_url):
386
# Block potentially malicious redirects
387
flash('Invalid redirect URL detected.', 'warning')
388
next_url = None
389
390
return self.render('admin/login.html', next_url=next_url)
391
```
392
393
### Dynamic Attribute Access
394
395
```python
396
from flask_admin.tools import rec_getattr
397
from flask_admin.helpers import prettify_class_name
398
399
class DynamicModelView(ModelView):
400
def __init__(self, model, *args, **kwargs):
401
super().__init__(model, *args, **kwargs)
402
403
# Auto-generate view name from model class
404
if not kwargs.get('name'):
405
self.name = prettify_class_name(model.__name__)
406
407
def _format_nested_attribute(self, view, context, model, name):
408
"""Custom formatter supporting nested attributes."""
409
# Use rec_getattr for nested attribute access like 'user.profile.name'
410
value = rec_getattr(model, name, default='N/A')
411
return str(value)
412
413
def scaffold_list_columns(self):
414
columns = super().scaffold_list_columns()
415
416
# Add formatters for nested attributes
417
nested_columns = [col for col in columns if '.' in col]
418
for col in nested_columns:
419
if col not in self.column_formatters:
420
self.column_formatters[col] = self._format_nested_attribute
421
422
return columns
423
```
424
425
### Custom Import Utilities
426
427
```python
428
from flask_admin.tools import import_attribute, import_module
429
from flask import current_app
430
431
class PluggableModelView(ModelView):
432
def __init__(self, model, *args, **kwargs):
433
super().__init__(model, *args, **kwargs)
434
435
# Load custom formatters from configuration
436
formatter_config = current_app.config.get('ADMIN_FORMATTERS', {})
437
438
for field_name, formatter_path in formatter_config.items():
439
try:
440
formatter_func = import_attribute(formatter_path)
441
self.column_formatters[field_name] = formatter_func
442
except (ImportError, AttributeError) as ex:
443
current_app.logger.warning(f'Failed to load formatter {formatter_path}: {ex}')
444
445
def load_custom_filters(self):
446
"""Load custom filters from plugins."""
447
filter_modules = current_app.config.get('ADMIN_FILTER_MODULES', [])
448
449
custom_filters = []
450
for module_name in filter_modules:
451
try:
452
module = import_module(module_name, required=False)
453
if module and hasattr(module, 'get_filters'):
454
filters = module.get_filters(self.model)
455
custom_filters.extend(filters)
456
except ImportError:
457
current_app.logger.warning(f'Failed to load filter module: {module_name}')
458
459
return custom_filters
460
```
461
462
### Template Context Enhancement
463
464
```python
465
from flask_admin.helpers import get_render_ctx, resolve_ctx
466
from flask import g
467
468
class EnhancedView(BaseView):
469
def render(self, template, **kwargs):
470
# Get current render context
471
ctx = get_render_ctx()
472
473
# Add custom context variables
474
enhanced_ctx = {
475
'current_user': getattr(g, 'user', None),
476
'app_version': current_app.config.get('VERSION', 'Unknown'),
477
'debug_mode': current_app.debug,
478
'custom_menu_items': self.get_custom_menu_items()
479
}
480
481
# Merge contexts
482
ctx.update(enhanced_ctx)
483
ctx.update(kwargs)
484
485
return super().render(template, **ctx)
486
487
def get_custom_menu_items(self):
488
"""Generate custom menu items based on user permissions."""
489
items = []
490
491
if hasattr(g, 'user') and g.user:
492
if g.user.can_access_reports:
493
items.append({
494
'name': 'Reports',
495
'url': '/admin/reports/',
496
'icon': 'fa-chart-bar'
497
})
498
499
return items
500
```
501
502
### Encoding/Decoding for Complex Parameters
503
504
```python
505
from flask_admin.tools import iterencode, iterdecode
506
from flask import request, url_for
507
508
class FilterableView(ModelView):
509
def apply_filters_from_url(self):
510
"""Apply filters from URL parameters."""
511
# Decode filter parameters
512
filter_param = request.args.get('filters')
513
514
if filter_param:
515
try:
516
# Decode filter tuple from URL
517
filter_ids = iterdecode(filter_param)
518
519
# Apply filters
520
for filter_id in filter_ids:
521
self.apply_filter(filter_id)
522
523
except (ValueError, TypeError):
524
# Invalid filter parameter
525
pass
526
527
def generate_filtered_url(self, active_filters):
528
"""Generate URL with encoded filter parameters."""
529
# Encode active filters for URL
530
if active_filters:
531
filter_param = iterencode(active_filters)
532
return url_for('.index_view', filters=filter_param)
533
534
return url_for('.index_view')
535
```