0
# Forms and Processing
1
2
Core form functionality including form definition, data processing, validation, and object population. These classes provide the foundation for all form handling in WTForms.
3
4
## Capabilities
5
6
### Form Classes
7
8
The main form classes that provide declarative form definition and processing capabilities.
9
10
```python { .api }
11
class Form:
12
"""
13
Declarative form class with metaclass support for field definition.
14
15
Parameters:
16
- formdata: Input data from client (multidict interface like request.form)
17
- obj: Object to populate fields from
18
- prefix: Optional prefix for all field names
19
- data: Dict of field data to pre-populate
20
- meta: Meta configuration overrides
21
- **kwargs: Additional field data
22
"""
23
def __init__(self, formdata=None, obj=None, prefix="", data=None, meta=None, **kwargs): ...
24
25
def validate(self, extra_validators=None) -> bool:
26
"""
27
Validate all fields and run validate_<fieldname> methods.
28
29
Parameters:
30
- extra_validators: Dict of field_name -> list of extra validators
31
32
Returns:
33
bool: True if all fields validate successfully
34
"""
35
36
def populate_obj(self, obj):
37
"""
38
Populate object attributes with form field data.
39
40
Parameters:
41
- obj: Object to populate (uses field names as attribute names)
42
"""
43
44
def process(self, formdata=None, obj=None, data=None, extra_filters=None, **kwargs):
45
"""
46
Process form data through all fields.
47
48
Parameters:
49
- formdata: Input data from client
50
- obj: Object to populate fields from
51
- data: Dict of field data
52
- extra_filters: Additional data filters to apply
53
- **kwargs: Additional field data
54
"""
55
56
# Dict-like field access
57
def __iter__(self): ...
58
def __contains__(self, name) -> bool: ...
59
def __getitem__(self, name) -> Field: ...
60
def __setitem__(self, name, value): ...
61
def __delitem__(self, name): ...
62
63
# Properties
64
data: dict # Dict of all field data
65
errors: dict # Dict of field errors
66
form_errors: list # Form-level validation errors
67
68
class BaseForm:
69
"""
70
Base form class providing core form behavior without metaclass.
71
72
Parameters:
73
- fields: Dict or sequence of 2-tuples of partially-constructed fields
74
- prefix: Optional prefix for all field names
75
- meta: Meta instance for configuration
76
"""
77
def __init__(self, fields, prefix="", meta=None): ...
78
79
def validate(self, extra_validators=None) -> bool:
80
"""Validate all fields, returns True if all fields validate."""
81
82
def populate_obj(self, obj):
83
"""Populate object attributes with form data."""
84
85
def process(self, formdata=None, obj=None, data=None, extra_filters=None, **kwargs):
86
"""Process form data through all fields."""
87
88
# Dict-like field access methods (same as Form)
89
def __iter__(self): ...
90
def __contains__(self, name) -> bool: ...
91
def __getitem__(self, name) -> Field: ...
92
def __setitem__(self, name, value): ...
93
def __delitem__(self, name): ...
94
95
# Properties
96
data: dict # Dict of all field data
97
errors: dict # Dict of field errors
98
form_errors: list # Form-level validation errors
99
```
100
101
### Form Usage Examples
102
103
#### Basic Form Definition and Processing
104
105
```python
106
from wtforms import Form, StringField, IntegerField, validators
107
108
class UserRegistrationForm(Form):
109
username = StringField('Username', [
110
validators.DataRequired(),
111
validators.Length(min=4, max=25)
112
])
113
email = StringField('Email Address', [
114
validators.DataRequired(),
115
validators.Email()
116
])
117
age = IntegerField('Age', [
118
validators.NumberRange(min=13, max=120)
119
])
120
121
# Process form submission
122
def handle_registration(request):
123
form = UserRegistrationForm(formdata=request.form)
124
125
if form.validate():
126
# Create user object
127
user = User()
128
form.populate_obj(user) # Sets user.username, user.email, user.age
129
user.save()
130
return redirect('/success')
131
else:
132
# Re-render form with errors
133
return render_template('register.html', form=form)
134
```
135
136
#### Form with Object Population
137
138
```python
139
def edit_user(request, user_id):
140
user = User.get(user_id)
141
form = UserRegistrationForm(formdata=request.form, obj=user)
142
143
if form.validate():
144
form.populate_obj(user)
145
user.save()
146
return redirect('/success')
147
148
return render_template('edit_user.html', form=form)
149
```
150
151
#### Custom Validation Methods
152
153
```python
154
class LoginForm(Form):
155
username = StringField('Username', [validators.DataRequired()])
156
password = StringField('Password', [validators.DataRequired()])
157
158
def validate_username(self, field):
159
"""Custom validation method for username field."""
160
if not User.exists(field.data):
161
raise ValidationError('Username does not exist.')
162
163
def validate_password(self, field):
164
"""Custom validation method for password field."""
165
user = User.get_by_username(self.username.data)
166
if user and not user.check_password(field.data):
167
raise ValidationError('Invalid password.')
168
```
169
170
#### Form with Prefixes
171
172
```python
173
# Useful for multiple forms on one page
174
billing_form = AddressForm(formdata=request.form, prefix='billing')
175
shipping_form = AddressForm(formdata=request.form, prefix='shipping')
176
177
if billing_form.validate() and shipping_form.validate():
178
# Process both forms
179
pass
180
```
181
182
#### Dynamic Field Access
183
184
```python
185
form = MyForm(formdata=request.form)
186
187
# Access fields dynamically
188
for field_name, field in form:
189
print(f"Field {field_name}: {field.data}")
190
191
# Check if field exists
192
if 'username' in form:
193
username_field = form['username']
194
195
# Access field data and errors
196
all_data = form.data # {'username': 'john', 'email': 'john@example.com'}
197
all_errors = form.errors # {'email': ['Invalid email address.']}
198
```
199
200
### Advanced Form Patterns
201
202
#### Form Inheritance
203
204
```python
205
class BaseUserForm(Form):
206
username = StringField('Username', [validators.DataRequired()])
207
email = StringField('Email', [validators.Email()])
208
209
class AdminUserForm(BaseUserForm):
210
is_admin = BooleanField('Admin privileges')
211
permissions = SelectMultipleField('Permissions', choices=[...])
212
```
213
214
#### Form Composition with FormField
215
216
```python
217
class AddressForm(Form):
218
street = StringField('Street')
219
city = StringField('City')
220
zipcode = StringField('Zip Code')
221
222
class UserForm(Form):
223
name = StringField('Name')
224
billing_address = FormField(AddressForm)
225
shipping_address = FormField(AddressForm)
226
227
# Access nested data
228
form = UserForm(formdata=request.form)
229
if form.validate():
230
billing_street = form.billing_address.street.data
231
shipping_city = form.shipping_address.city.data
232
```
233
234
### Error Handling
235
236
Form validation produces structured error information that can be used for display:
237
238
```python
239
form = MyForm(formdata=request.form)
240
if not form.validate():
241
# Field-level errors
242
for field_name, field_errors in form.errors.items():
243
for error in field_errors:
244
print(f"Error in {field_name}: {error}")
245
246
# Form-level errors (from validate_<fieldname> methods)
247
for error in form.form_errors:
248
print(f"Form error: {error}")
249
250
# Individual field errors
251
if form.username.errors:
252
print("Username errors:", form.username.errors)
253
```