0
# Forms and Field Types
1
2
Advanced form system with custom field types, validation, widgets, and CSRF protection for Flask-Admin interfaces.
3
4
## Capabilities
5
6
### Base Form Classes
7
8
Foundation form classes providing translation support and CSRF protection.
9
10
```python { .api }
11
class BaseForm:
12
def __init__(self, formdata=None, obj=None, prefix='', **kwargs):
13
"""
14
Base form class with translation support.
15
16
Args:
17
formdata: Input data for form
18
obj: Object to populate form from
19
prefix (str): Field name prefix
20
**kwargs: Additional form arguments
21
"""
22
23
class SecureForm(BaseForm):
24
"""
25
Form with CSRF protection enabled.
26
Automatically includes and validates CSRF tokens.
27
"""
28
```
29
30
### Custom Field Types
31
32
Enhanced field types for common admin interface requirements.
33
34
```python { .api }
35
class DateTimeField:
36
def __init__(
37
self,
38
label=None,
39
validators=None,
40
format=None,
41
**kwargs
42
):
43
"""
44
Enhanced datetime field with picker widget.
45
46
Args:
47
label (str, optional): Field label
48
validators (list, optional): Field validators
49
format (str, optional): Date/time format string
50
**kwargs: Additional field arguments
51
"""
52
53
class TimeField:
54
def __init__(
55
self,
56
label=None,
57
validators=None,
58
formats=None,
59
default_format=None,
60
widget_format=None,
61
**kwargs
62
):
63
"""
64
Time field with multiple format support.
65
66
Args:
67
label (str, optional): Field label
68
validators (list, optional): Field validators
69
formats (list, optional): Accepted time formats
70
default_format (str, optional): Default format for parsing
71
widget_format (str, optional): Format for widget display
72
**kwargs: Additional field arguments
73
"""
74
75
class Select2Field:
76
def __init__(
77
self,
78
label=None,
79
validators=None,
80
coerce=None,
81
choices=None,
82
allow_blank=False,
83
blank_text=None,
84
**kwargs
85
):
86
"""
87
Select2 styled select field with enhanced UI.
88
89
Args:
90
label (str, optional): Field label
91
validators (list, optional): Field validators
92
coerce (function, optional): Value coercion function
93
choices (list, optional): Available choices
94
allow_blank (bool): Allow empty selection
95
blank_text (str, optional): Text for blank option
96
**kwargs: Additional field arguments
97
"""
98
99
class Select2TagsField:
100
def __init__(
101
self,
102
label=None,
103
validators=None,
104
save_as_list=False,
105
coerce=None,
106
allow_duplicates=False,
107
**kwargs
108
):
109
"""
110
Select2 tags field for multi-value input.
111
112
Args:
113
label (str, optional): Field label
114
validators (list, optional): Field validators
115
save_as_list (bool): Save as list instead of string
116
coerce (function, optional): Value coercion function
117
allow_duplicates (bool): Allow duplicate tags
118
**kwargs: Additional field arguments
119
"""
120
121
class JSONField:
122
"""
123
JSON data field with validation and pretty formatting.
124
Inherits from TextAreaField with JSON-specific processing.
125
"""
126
```
127
128
### Form Validators
129
130
Custom validators for Flask-Admin form fields.
131
132
```python { .api }
133
class FieldListInputRequired:
134
"""
135
Validator for FieldList to ensure at least one item is present.
136
"""
137
138
def __init__(self, message=None):
139
"""
140
Initialize validator.
141
142
Args:
143
message (str, optional): Custom validation error message
144
"""
145
146
def __call__(self, form, field):
147
"""
148
Validate field has at least one entry.
149
150
Args:
151
form: Form instance
152
field: Field being validated
153
154
Raises:
155
ValidationError: If field is empty
156
"""
157
```
158
159
### Form Utilities
160
161
Utility classes and functions for form management and configuration.
162
163
```python { .api }
164
class FormOpts:
165
"""
166
Form options container for configuration.
167
"""
168
169
def recreate_field(unbound):
170
"""
171
Recreate UnboundField instance.
172
173
Args:
174
unbound: UnboundField to recreate
175
176
Returns:
177
UnboundField: New field instance
178
"""
179
```
180
181
## Usage Examples
182
183
### Custom Form with Validation
184
185
```python
186
from flask_admin.form import BaseForm, SecureForm
187
from flask_admin.form.fields import Select2Field, JSONField
188
from wtforms import StringField, TextAreaField, BooleanField
189
from wtforms.validators import DataRequired, Email, Length
190
191
class UserForm(SecureForm):
192
name = StringField('Full Name', validators=[
193
DataRequired(),
194
Length(min=2, max=100)
195
])
196
197
email = StringField('Email Address', validators=[
198
DataRequired(),
199
Email()
200
])
201
202
role = Select2Field('Role', choices=[
203
('admin', 'Administrator'),
204
('user', 'Regular User'),
205
('guest', 'Guest User')
206
], coerce=str)
207
208
is_active = BooleanField('Active User')
209
210
preferences = JSONField('User Preferences', description='JSON configuration data')
211
212
bio = TextAreaField('Biography', description='User biography and notes')
213
214
# Use in model view
215
class UserModelView(ModelView):
216
form = UserForm
217
form_args = {
218
'name': {'render_kw': {'placeholder': 'Enter full name'}},
219
'email': {'render_kw': {'placeholder': 'user@example.com'}}
220
}
221
```
222
223
### Advanced Field Configuration
224
225
```python
226
from flask_admin.form.fields import DateTimeField, TimeField, Select2TagsField
227
from datetime import datetime
228
229
class EventForm(SecureForm):
230
title = StringField('Event Title', validators=[DataRequired()])
231
232
start_time = DateTimeField(
233
'Start Time',
234
format='%Y-%m-%d %H:%M',
235
default=datetime.now
236
)
237
238
duration = TimeField(
239
'Duration',
240
formats=['%H:%M', '%H:%M:%S'],
241
default_format='%H:%M'
242
)
243
244
tags = Select2TagsField(
245
'Tags',
246
save_as_list=True,
247
coerce=str,
248
description='Enter tags separated by commas'
249
)
250
251
location = Select2Field(
252
'Location',
253
choices=[], # Will be populated dynamically
254
allow_blank=True,
255
blank_text='Select a location...'
256
)
257
258
class EventModelView(ModelView):
259
form = EventForm
260
261
def create_form(self, obj=None):
262
form = super().create_form(obj)
263
# Populate location choices dynamically
264
form.location.choices = [
265
(loc.id, loc.name) for loc in Location.query.all()
266
]
267
return form
268
269
def edit_form(self, obj=None):
270
form = super().edit_form(obj)
271
# Populate location choices dynamically
272
form.location.choices = [
273
(loc.id, loc.name) for loc in Location.query.all()
274
]
275
return form
276
```
277
278
### Form Widget Customization
279
280
```python
281
class ProductModelView(ModelView):
282
form_widget_args = {
283
'name': {
284
'placeholder': 'Product name',
285
'class': 'form-control-lg'
286
},
287
'description': {
288
'rows': 5,
289
'placeholder': 'Detailed product description...'
290
},
291
'price': {
292
'step': '0.01',
293
'min': '0',
294
'placeholder': '0.00'
295
},
296
'category': {
297
'data-placeholder': 'Choose category...',
298
'class': 'select2-enhanced'
299
}
300
}
301
302
form_args = {
303
'price': {
304
'validators': [DataRequired(), NumberRange(min=0)]
305
},
306
'name': {
307
'validators': [DataRequired(), Length(max=200)]
308
}
309
}
310
```
311
312
### Custom Field Override
313
314
```python
315
from wtforms import SelectField, TextAreaField
316
from flask_admin.form.fields import Select2Field
317
318
class ArticleModelView(ModelView):
319
form_overrides = {
320
'status': Select2Field, # Use Select2 instead of regular select
321
'content': TextAreaField # Use textarea for content field
322
}
323
324
form_args = {
325
'status': {
326
'choices': [
327
('draft', 'Draft'),
328
('published', 'Published'),
329
('archived', 'Archived')
330
],
331
'coerce': str
332
},
333
'content': {
334
'render_kw': {
335
'rows': 10,
336
'class': 'editor'
337
}
338
}
339
}
340
```
341
342
### JSON Field Usage
343
344
```python
345
class ConfigModelView(ModelView):
346
form_overrides = {
347
'settings': JSONField
348
}
349
350
form_args = {
351
'settings': {
352
'description': 'Configuration in JSON format',
353
'render_kw': {
354
'rows': 8,
355
'placeholder': '{\n "key": "value"\n}'
356
}
357
}
358
}
359
360
def on_model_change(self, form, model, is_created):
361
# Validate JSON before saving
362
try:
363
if model.settings:
364
import json
365
json.loads(model.settings)
366
except ValueError as e:
367
raise ValidationError(f'Invalid JSON: {e}')
368
```