0
# Compound Field Types
1
2
Advanced field types for complex data structures in Schematics. These types handle collections, nested models, and polymorphic data with recursive validation and conversion.
3
4
## Capabilities
5
6
### List Fields
7
8
Handle arrays and sequences with typed elements and size constraints.
9
10
```python { .api }
11
class ListType(BaseType):
12
"""
13
Field for storing lists/arrays of typed items.
14
15
Validates list size and applies field validation to each element.
16
Supports nested validation with any field type.
17
"""
18
19
def __init__(self, field, min_size=None, max_size=None, **kwargs):
20
"""
21
Initialize list field.
22
23
Args:
24
field (BaseType): Field type for list elements
25
min_size (int, optional): Minimum list length
26
max_size (int, optional): Maximum list length
27
**kwargs: Base field options
28
"""
29
```
30
31
### Dictionary Fields
32
33
Handle key-value mappings with optional typed values.
34
35
```python { .api }
36
class DictType(BaseType):
37
"""
38
Field for storing mappings/dictionaries.
39
40
Supports typed values and validates dictionary structure.
41
Keys are typically strings, values can be typed using field parameter.
42
"""
43
44
def __init__(self, field=None, **kwargs):
45
"""
46
Initialize dictionary field.
47
48
Args:
49
field (BaseType, optional): Field type for dictionary values
50
**kwargs: Base field options
51
"""
52
```
53
54
### Nested Model Fields
55
56
Handle embedded model instances with recursive validation.
57
58
```python { .api }
59
class ModelType(BaseType):
60
"""
61
Field that holds a model instance with nested validation.
62
63
Enables composition of models and recursive data structures.
64
Validates nested model according to its field definitions.
65
"""
66
67
def __init__(self, model_class, **kwargs):
68
"""
69
Initialize model field.
70
71
Args:
72
model_class (Model): Model class for nested instances
73
**kwargs: Base field options
74
"""
75
```
76
77
### Polymorphic Model Fields
78
79
Handle multiple model types with dynamic type resolution.
80
81
```python { .api }
82
class PolyModelType(BaseType):
83
"""
84
Field accepting instances of multiple model types.
85
86
Supports polymorphic data structures where the exact model type
87
is determined at runtime based on data content or explicit type hints.
88
"""
89
90
def __init__(self, model_spec, **kwargs):
91
"""
92
Initialize polymorphic model field.
93
94
Args:
95
model_spec (dict): Mapping of type identifiers to model classes
96
**kwargs: Base field options
97
"""
98
```
99
100
### Union Fields
101
102
Handle values that can be one of multiple types.
103
104
```python { .api }
105
class UnionType(BaseType):
106
"""
107
Field that accepts multiple type alternatives with fallback logic.
108
109
Attempts conversion with each type until one succeeds,
110
providing flexible input handling for ambiguous data.
111
"""
112
113
def __init__(self, types, **kwargs):
114
"""
115
Initialize union field.
116
117
Args:
118
types (list): List of field types to attempt
119
**kwargs: Base field options
120
"""
121
```
122
123
### Base Compound Type
124
125
Base class providing common functionality for compound types.
126
127
```python { .api }
128
class CompoundType(BaseType):
129
"""
130
Base class for compound field types containing other fields.
131
132
Provides infrastructure for recursive validation and conversion
133
of nested data structures.
134
"""
135
136
def __init__(self, **kwargs):
137
"""
138
Initialize compound field.
139
140
Args:
141
**kwargs: Base field options
142
"""
143
```
144
145
## Usage Examples
146
147
### List Validation
148
149
```python
150
from schematics.models import Model
151
from schematics.types import StringType, ListType, IntType
152
153
class BlogPost(Model):
154
title = StringType(required=True)
155
tags = ListType(StringType(), min_size=1, max_size=10)
156
ratings = ListType(IntType(min_value=1, max_value=5))
157
158
# Valid data
159
post = BlogPost({
160
'title': 'My Blog Post',
161
'tags': ['python', 'programming', 'web'],
162
'ratings': [4, 5, 3, 4]
163
})
164
post.validate() # Success
165
166
# Each list element is validated according to field type
167
invalid_post = BlogPost({
168
'title': 'Test',
169
'tags': ['valid_tag', ''], # Empty string fails StringType validation
170
'ratings': [1, 6] # 6 exceeds max_value=5
171
})
172
# post.validate() would raise ValidationError
173
```
174
175
### Dictionary Fields
176
177
```python
178
from schematics.types import DictType, StringType
179
180
class Configuration(Model):
181
metadata = DictType() # Any dict values allowed
182
settings = DictType(StringType()) # String values only
183
184
config = Configuration({
185
'metadata': {'version': '1.0', 'author': 'John', 'count': 42},
186
'settings': {'theme': 'dark', 'language': 'en'}
187
})
188
config.validate()
189
```
190
191
### Nested Models
192
193
```python
194
class Address(Model):
195
street = StringType(required=True)
196
city = StringType(required=True)
197
country = StringType(required=True)
198
199
class Person(Model):
200
name = StringType(required=True)
201
address = ModelType(Address, required=True)
202
203
# Nested validation
204
person_data = {
205
'name': 'John Doe',
206
'address': {
207
'street': '123 Main St',
208
'city': 'Anytown',
209
'country': 'USA'
210
}
211
}
212
213
person = Person(person_data)
214
person.validate() # Validates both Person and nested Address
215
216
# Access nested data
217
print(person.address.city) # 'Anytown'
218
print(person.to_primitive()) # Includes nested address data
219
```
220
221
### Complex Nested Structures
222
223
```python
224
class Comment(Model):
225
author = StringType(required=True)
226
text = StringType(required=True)
227
timestamp = DateTimeType()
228
229
class Article(Model):
230
title = StringType(required=True)
231
content = StringType(required=True)
232
comments = ListType(ModelType(Comment))
233
tags = ListType(StringType())
234
metadata = DictType(StringType())
235
236
# Complex nested data
237
article_data = {
238
'title': 'Advanced Python',
239
'content': 'Python is a powerful language...',
240
'comments': [
241
{'author': 'Alice', 'text': 'Great article!'},
242
{'author': 'Bob', 'text': 'Very helpful, thanks.'}
243
],
244
'tags': ['python', 'programming', 'tutorial'],
245
'metadata': {'category': 'programming', 'difficulty': 'intermediate'}
246
}
247
248
article = Article(article_data)
249
article.validate() # Validates entire nested structure
250
```
251
252
### Polymorphic Models
253
254
```python
255
class Vehicle(Model):
256
make = StringType(required=True)
257
model = StringType(required=True)
258
259
class Car(Vehicle):
260
doors = IntType(min_value=2, max_value=5)
261
262
class Motorcycle(Vehicle):
263
engine_size = IntType(min_value=50)
264
265
class Fleet(Model):
266
name = StringType(required=True)
267
vehicles = ListType(PolyModelType({
268
'car': Car,
269
'motorcycle': Motorcycle
270
}))
271
272
# Mixed vehicle types
273
fleet_data = {
274
'name': 'City Fleet',
275
'vehicles': [
276
{'_type': 'car', 'make': 'Toyota', 'model': 'Camry', 'doors': 4},
277
{'_type': 'motorcycle', 'make': 'Honda', 'model': 'CBR', 'engine_size': 600}
278
]
279
}
280
281
fleet = Fleet(fleet_data)
282
fleet.validate() # Each vehicle validated according to its specific type
283
```
284
285
### Union Types for Flexible Input
286
287
```python
288
from schematics.types import UnionType
289
290
class FlexibleRecord(Model):
291
# Field can accept either string or integer
292
identifier = UnionType([StringType(), IntType()])
293
# Field can be either a single string or list of strings
294
tags = UnionType([StringType(), ListType(StringType())])
295
296
# Various input formats accepted
297
record1 = FlexibleRecord({
298
'identifier': 'ABC123', # String
299
'tags': 'single-tag' # Single string
300
})
301
302
record2 = FlexibleRecord({
303
'identifier': 12345, # Integer
304
'tags': ['tag1', 'tag2'] # List of strings
305
})
306
307
record1.validate() # Success
308
record2.validate() # Success
309
```