0
# Validation
1
2
Marshmallow provides a comprehensive validation framework with built-in validators for common patterns and support for custom validation logic. Validators can be applied to individual fields or entire schemas.
3
4
## Capabilities
5
6
### Base Validator Classes
7
8
All validators inherit from the base Validator class, which defines the validation interface.
9
10
```python { .api }
11
class Validator:
12
"""
13
Abstract base class for all validators.
14
15
Attributes:
16
- error: str, default error message for validation failures
17
"""
18
19
def __call__(self, value):
20
"""
21
Perform validation on a value.
22
23
Parameters:
24
- value: the value to validate
25
26
Raises:
27
ValidationError: if validation fails
28
"""
29
```
30
31
### Composite Validators
32
33
Validators that combine multiple validation rules.
34
35
```python { .api }
36
class And(Validator):
37
"""
38
Compose multiple validators where all must pass.
39
40
Parameters:
41
- validators: sequence of validators to combine
42
- error: str, custom error message
43
"""
44
45
def __init__(self, *validators, error=None):
46
pass
47
```
48
49
### String Validators
50
51
Validators for text data with pattern matching and format validation.
52
53
```python { .api }
54
class Email(Validator):
55
"""
56
Validate email addresses using regex pattern matching.
57
58
Parameters:
59
- error: str, custom error message
60
"""
61
62
def __init__(self, *, error=None):
63
pass
64
65
class URL(Validator):
66
"""
67
Validate URLs with configurable options.
68
69
Parameters:
70
- relative: bool, allow relative URLs (default: False)
71
- absolute: bool, allow absolute URLs (default: True)
72
- schemes: set, valid URL schemes (default: http, https, ftp, ftps)
73
- require_tld: bool, require top-level domain (default: True)
74
- error: str, custom error message
75
"""
76
77
def __init__(self, *, relative=False, absolute=True, schemes=None,
78
require_tld=True, error=None):
79
pass
80
81
class Regexp(Validator):
82
"""
83
Validate against a regular expression pattern.
84
85
Parameters:
86
- regex: str or compiled regex, regular expression pattern
87
- flags: int, regex flags (re.IGNORECASE, etc.)
88
- error: str, custom error message
89
"""
90
91
def __init__(self, regex, *, flags=0, error=None):
92
pass
93
```
94
95
### Numeric Validators
96
97
Validators for numeric ranges and constraints.
98
99
```python { .api }
100
class Range(Validator):
101
"""
102
Validate that a number is within a specified range.
103
104
Parameters:
105
- min: number, minimum value (inclusive by default)
106
- max: number, maximum value (inclusive by default)
107
- min_inclusive: bool, whether minimum is inclusive (default: True)
108
- max_inclusive: bool, whether maximum is inclusive (default: True)
109
- error: str, custom error message
110
"""
111
112
def __init__(self, min=None, max=None, *, min_inclusive=True,
113
max_inclusive=True, error=None):
114
pass
115
```
116
117
### Collection Validators
118
119
Validators for sequences, sets, and collection properties.
120
121
```python { .api }
122
class Length(Validator):
123
"""
124
Validate the length of strings, lists, and other collections.
125
126
Parameters:
127
- min: int, minimum length
128
- max: int, maximum length
129
- equal: int, exact length required
130
- error: str, custom error message
131
"""
132
133
def __init__(self, min=None, max=None, *, equal=None, error=None):
134
pass
135
136
class OneOf(Validator):
137
"""
138
Validate that a value is one of a given set of choices.
139
140
Parameters:
141
- choices: iterable, valid choice values
142
- labels: iterable, human-readable labels for choices
143
- error: str, custom error message
144
"""
145
146
def __init__(self, choices, *, labels=None, error=None):
147
pass
148
149
class NoneOf(Validator):
150
"""
151
Validate that a value is not one of a given set of choices.
152
153
Parameters:
154
- choices: iterable, invalid choice values
155
- labels: iterable, human-readable labels for choices
156
- error: str, custom error message
157
"""
158
159
def __init__(self, choices, *, labels=None, error=None):
160
pass
161
162
class ContainsOnly(Validator):
163
"""
164
Validate that an iterable contains only the given choices.
165
166
Parameters:
167
- choices: iterable, valid choice values
168
- labels: iterable, human-readable labels for choices
169
- error: str, custom error message
170
"""
171
172
def __init__(self, choices, *, labels=None, error=None):
173
pass
174
175
class ContainsNoneOf(Validator):
176
"""
177
Validate that an iterable contains none of the given choices.
178
179
Parameters:
180
- choices: iterable, invalid choice values
181
- labels: iterable, human-readable labels for choices
182
- error: str, custom error message
183
"""
184
185
def __init__(self, choices, *, labels=None, error=None):
186
pass
187
```
188
189
### Equality and Predicate Validators
190
191
Validators for equality comparison and custom predicate functions.
192
193
```python { .api }
194
class Equal(Validator):
195
"""
196
Validate that a value equals a specific comparable value.
197
198
Parameters:
199
- comparable: the value to compare against
200
- error: str, custom error message
201
"""
202
203
def __init__(self, comparable, *, error=None):
204
pass
205
206
class Predicate(Validator):
207
"""
208
Validate using a custom predicate method on the value.
209
210
Parameters:
211
- method: str, method name to call on the value
212
- error: str, custom error message
213
"""
214
215
def __init__(self, method, *, error=None):
216
pass
217
```
218
219
## Usage Examples
220
221
### Field-Level Validation
222
223
```python
224
from marshmallow import Schema, fields, validate
225
226
class UserSchema(Schema):
227
# Single validator
228
username = fields.Str(validate=validate.Length(min=3, max=20))
229
230
# Multiple validators using And
231
password = fields.Str(validate=validate.And(
232
validate.Length(min=8),
233
validate.Regexp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)')
234
))
235
236
# Choice validation
237
status = fields.Str(validate=validate.OneOf(['active', 'inactive', 'pending']))
238
239
# Numeric range
240
age = fields.Int(validate=validate.Range(min=18, max=120))
241
242
# Email validation
243
email = fields.Str(validate=validate.Email())
244
245
# URL validation
246
website = fields.Str(validate=validate.URL(schemes=['http', 'https']))
247
248
# Custom lambda validator
249
score = fields.Float(validate=lambda x: 0 <= x <= 100)
250
```
251
252
### Collection Validation
253
254
```python
255
class ArticleSchema(Schema):
256
# List length validation
257
tags = fields.List(fields.Str(), validate=validate.Length(min=1, max=10))
258
259
# List item validation
260
categories = fields.List(
261
fields.Str(validate=validate.OneOf(['tech', 'science', 'business']))
262
)
263
264
# Nested validation with ContainsOnly
265
valid_tags = fields.List(
266
fields.Str(),
267
validate=validate.ContainsOnly(['python', 'javascript', 'rust', 'go'])
268
)
269
```
270
271
### Custom Validators
272
273
```python
274
def validate_even(value):
275
"""Custom validator function."""
276
if value % 2 != 0:
277
raise ValidationError('Value must be even.')
278
279
class CustomValidator(validate.Validator):
280
"""Custom validator class."""
281
282
def __call__(self, value):
283
if not self.is_valid(value):
284
raise ValidationError(self.error or 'Validation failed')
285
286
def is_valid(self, value):
287
# Custom validation logic
288
return True
289
290
class NumberSchema(Schema):
291
# Using custom function validator
292
even_number = fields.Int(validate=validate_even)
293
294
# Using custom class validator
295
special_value = fields.Str(validate=CustomValidator())
296
```
297
298
### Schema-Level Validation
299
300
Schema-level validators are applied after field-level validation using the `@validates_schema` decorator.
301
302
```python
303
from marshmallow import Schema, fields, validates_schema, ValidationError
304
305
class EventSchema(Schema):
306
start_date = fields.Date()
307
end_date = fields.Date()
308
309
@validates_schema
310
def validate_dates(self, data, **kwargs):
311
"""Validate that end_date is after start_date."""
312
if data.get('end_date') and data.get('start_date'):
313
if data['end_date'] < data['start_date']:
314
raise ValidationError('End date must be after start date.')
315
```
316
317
### Conditional Validation
318
319
```python
320
class OrderSchema(Schema):
321
order_type = fields.Str(validate=validate.OneOf(['online', 'store']))
322
shipping_address = fields.Str()
323
store_location = fields.Str()
324
325
@validates_schema
326
def validate_order_requirements(self, data, **kwargs):
327
"""Validate requirements based on order type."""
328
if data.get('order_type') == 'online' and not data.get('shipping_address'):
329
raise ValidationError('Shipping address required for online orders.')
330
331
if data.get('order_type') == 'store' and not data.get('store_location'):
332
raise ValidationError('Store location required for store orders.')
333
```
334
335
### Error Message Customization
336
337
```python
338
class ProductSchema(Schema):
339
name = fields.Str(
340
required=True,
341
validate=validate.Length(min=2, max=100),
342
error_messages={
343
'required': 'Product name is required.',
344
'validator_failed': 'Product name must be between 2 and 100 characters.'
345
}
346
)
347
348
price = fields.Decimal(
349
validate=validate.Range(min=0),
350
error_messages={
351
'validator_failed': 'Price must be a positive number.'
352
}
353
)
354
355
category = fields.Str(
356
validate=validate.OneOf(['books', 'electronics', 'clothing']),
357
error_messages={
358
'validator_failed': 'Category must be one of: books, electronics, clothing.'
359
}
360
)
361
```