0
# Models and Marshalling
1
2
Data model definition and automatic marshalling system for request/response handling. Flask-RESTPlus provides model classes for defining data structures and marshalling functions for automatic serialization and validation.
3
4
## Capabilities
5
6
### Model Classes
7
8
Base classes for defining data models used in request validation and response marshalling.
9
10
```python { .api }
11
class Model(dict):
12
def __init__(self, name, *args, mask=None, **kwargs):
13
"""
14
Initialize a field-based model.
15
16
Args:
17
name (str): Model name for documentation
18
*args: Additional positional arguments
19
mask (str or Mask, optional): Default model mask
20
**kwargs: Field definitions
21
"""
22
23
@classmethod
24
def inherit(cls, name, *parents):
25
"""
26
Create a new model inheriting from parent models using Swagger composition.
27
28
Args:
29
name (str): New model name
30
*parents (Model): Parent models to inherit from
31
32
Returns:
33
Model: New inherited model
34
"""
35
36
def clone(self, name=None, *parents):
37
"""
38
Clone this model by duplicating all fields.
39
40
Args:
41
name (str, optional): New model name
42
*parents (Model): Additional parent models
43
44
Returns:
45
Model: Cloned model
46
"""
47
48
def validate(self, data, resolver=None, format_checker=None):
49
"""
50
Validate data against the model schema.
51
52
Args:
53
data: Data to validate
54
resolver: JSON schema resolver
55
format_checker: JSON schema format checker
56
57
Raises:
58
ValidationError: If validation fails
59
"""
60
61
def get_parent(self, name):
62
"""
63
Get a parent model by name.
64
65
Args:
66
name (str): Parent model name
67
68
Returns:
69
Model: Parent model instance
70
"""
71
72
@property
73
def ancestors(self):
74
"""
75
Return the inheritance tree as a set.
76
77
Returns:
78
set: Set of ancestor model names
79
"""
80
81
@property
82
def __schema__(self):
83
"""
84
Return the JSON Schema representation.
85
86
Returns:
87
dict: JSON Schema with inheritance support
88
"""
89
90
@property
91
def resolved(self):
92
"""
93
Get the resolved model definition.
94
95
Returns:
96
dict: Resolved field definitions
97
"""
98
99
class OrderedModel(Model):
100
def __init__(self, name, *args, mask=None, **kwargs):
101
"""
102
Initialize an ordered model that preserves field insertion order.
103
Inherits all methods from Model but maintains field ordering.
104
105
Args:
106
name (str): Model name for documentation
107
*args: Additional positional arguments
108
mask (str or Mask, optional): Default model mask
109
**kwargs: Field definitions in order
110
"""
111
112
class SchemaModel:
113
def __init__(self, name, schema=None):
114
"""
115
Initialize a model based on a JSON schema definition.
116
Unlike Model/OrderedModel, this doesn't manage fields directly.
117
118
Args:
119
name (str): Model name for documentation
120
schema (dict, optional): JSON schema definition
121
"""
122
123
@classmethod
124
def inherit(cls, name, *parents):
125
"""
126
Create a new schema model inheriting from parent models.
127
128
Args:
129
name (str): New model name
130
*parents (SchemaModel): Parent models to inherit from
131
132
Returns:
133
SchemaModel: New inherited model
134
"""
135
136
def validate(self, data, resolver=None, format_checker=None):
137
"""
138
Validate data against the schema.
139
140
Args:
141
data: Data to validate
142
resolver: JSON schema resolver
143
format_checker: JSON schema format checker
144
145
Raises:
146
ValidationError: If validation fails
147
"""
148
149
@property
150
def __schema__(self):
151
"""
152
Return the stored JSON schema.
153
154
Returns:
155
dict: JSON Schema definition
156
"""
157
158
@property
159
def ancestors(self):
160
"""
161
Return the inheritance tree as a set.
162
163
Returns:
164
set: Set of ancestor model names
165
"""
166
```
167
168
### Marshalling Functions
169
170
Functions for serializing Python objects to JSON responses using field definitions.
171
172
```python { .api }
173
def marshal(data, fields, envelope=None, skip_none=False, mask=None, ordered=False):
174
"""
175
Marshal data using field definitions.
176
177
Args:
178
data: The data to marshal (dict, list, or object)
179
fields (dict): Field definitions for marshalling
180
envelope (str, optional): Envelope key for response wrapping
181
skip_none (bool): Skip None values in output
182
mask (str, optional): Field mask for partial responses
183
ordered (bool): Preserve field ordering
184
185
Returns:
186
dict or list: Marshalled data
187
"""
188
189
def marshal_with(fields, as_list=False, code=200, description=None, **kwargs):
190
"""
191
Decorator for automatic response marshalling.
192
193
Args:
194
fields (dict or Model): Fields for marshalling
195
as_list (bool): Marshal response as a list
196
code (int): HTTP status code for successful response
197
description (str, optional): Response description
198
**kwargs: Additional marshal options (envelope, skip_none, mask, ordered)
199
200
Returns:
201
callable: Decorator function
202
"""
203
204
def marshal_with_field(field, **kwargs):
205
"""
206
Decorator for marshalling with a single field.
207
208
Args:
209
field (Field): Single field for marshalling
210
**kwargs: Additional marshal options
211
212
Returns:
213
callable: Decorator function
214
"""
215
```
216
217
### Response Masking
218
219
Response field masking system for partial responses and field filtering.
220
221
```python { .api }
222
class Mask:
223
def __init__(self, mask=None, skip=False, **kwargs):
224
"""
225
Initialize a field mask.
226
227
Args:
228
mask (str, optional): Mask string (e.g., "field1,field2{subfield}")
229
skip (bool): Skip masked fields instead of including them
230
**kwargs: Additional mask options
231
"""
232
233
def parse(self, mask):
234
"""
235
Parse a mask string.
236
237
Args:
238
mask (str): Mask string to parse
239
240
Returns:
241
dict: Parsed mask structure
242
"""
243
244
def apply(self, data):
245
"""
246
Apply the mask to data.
247
248
Args:
249
data: Data to mask
250
251
Returns:
252
Masked data
253
"""
254
255
def filter_data(self, data):
256
"""
257
Filter data according to the mask.
258
259
Args:
260
data: Data to filter
261
262
Returns:
263
Filtered data
264
"""
265
266
def apply_mask(data, mask, skip=False):
267
"""
268
Apply a field mask to data.
269
270
Args:
271
data: Data to mask
272
mask (str or Mask): Field mask
273
skip (bool): Skip masked fields
274
275
Returns:
276
Masked data
277
"""
278
```
279
280
## Usage Examples
281
282
### Basic Model Definition
283
284
```python
285
from flask_restplus import Api, fields
286
287
api = Api()
288
289
# Define a simple model
290
user_model = api.model('User', {
291
'id': fields.Integer(required=True, description='User ID'),
292
'name': fields.String(required=True, description='User name'),
293
'email': fields.String(required=True, description='Email address'),
294
'active': fields.Boolean(description='Account status')
295
})
296
297
# Define a nested model
298
post_model = api.model('Post', {
299
'id': fields.Integer(required=True, description='Post ID'),
300
'title': fields.String(required=True, description='Post title'),
301
'content': fields.String(description='Post content'),
302
'author': fields.Nested(user_model, description='Post author'),
303
'tags': fields.List(fields.String, description='Post tags'),
304
'created_at': fields.DateTime(description='Creation timestamp')
305
})
306
```
307
308
### Model Inheritance
309
310
```python
311
from flask_restplus import Api, fields
312
313
api = Api()
314
315
# Base model
316
base_model = api.model('BaseModel', {
317
'id': fields.Integer(required=True, description='Resource ID'),
318
'created_at': fields.DateTime(description='Creation timestamp'),
319
'updated_at': fields.DateTime(description='Last update timestamp')
320
})
321
322
# Inherited model
323
user_model = api.inherit('User', base_model, {
324
'name': fields.String(required=True, description='User name'),
325
'email': fields.String(required=True, description='Email address'),
326
})
327
328
# Multiple inheritance
329
admin_model = api.inherit('Admin', user_model, {
330
'permissions': fields.List(fields.String, description='Admin permissions'),
331
'is_super_admin': fields.Boolean(description='Super admin status')
332
})
333
```
334
335
### Model Cloning
336
337
```python
338
from flask_restplus import Api, fields
339
340
api = Api()
341
342
user_model = api.model('User', {
343
'id': fields.Integer(required=True),
344
'name': fields.String(required=True),
345
'email': fields.String(required=True),
346
'password': fields.String(required=True)
347
})
348
349
# Clone model without password field for responses
350
user_public = api.clone('UserPublic', user_model)
351
del user_public['password']
352
353
# Or create a new model with modifications
354
user_update = api.clone('UserUpdate', user_model, {
355
'password': fields.String(description='New password (optional)')
356
})
357
# Make all fields optional for updates
358
for field_name, field in user_update.items():
359
field.required = False
360
```
361
362
### Response Marshalling
363
364
```python
365
from flask_restplus import Api, Resource, fields, marshal_with
366
367
api = Api()
368
369
user_model = api.model('User', {
370
'id': fields.Integer,
371
'name': fields.String,
372
'email': fields.String
373
})
374
375
@api.route('/users/<int:user_id>')
376
class User(Resource):
377
@api.marshal_with(user_model)
378
def get(self, user_id):
379
# Return raw data - will be automatically marshalled
380
user_data = {
381
'id': user_id,
382
'name': 'John Doe',
383
'email': 'john@example.com',
384
'internal_field': 'hidden' # Not in model, will be filtered out
385
}
386
return user_data
387
388
@api.route('/users')
389
class UserList(Resource):
390
@api.marshal_list_with(user_model)
391
def get(self):
392
# Return list of raw data
393
users = [
394
{'id': 1, 'name': 'John', 'email': 'john@example.com'},
395
{'id': 2, 'name': 'Jane', 'email': 'jane@example.com'}
396
]
397
return users
398
```
399
400
### Manual Marshalling
401
402
```python
403
from flask_restplus import Api, fields, marshal
404
405
api = Api()
406
407
user_fields = {
408
'id': fields.Integer,
409
'name': fields.String,
410
'email': fields.String
411
}
412
413
# Manual marshalling
414
user_data = {'id': 1, 'name': 'John', 'email': 'john@example.com', 'secret': 'hidden'}
415
marshalled = marshal(user_data, user_fields)
416
# Result: {'id': 1, 'name': 'John', 'email': 'john@example.com'}
417
418
# Marshal with envelope
419
marshalled_with_envelope = marshal(user_data, user_fields, envelope='user')
420
# Result: {'user': {'id': 1, 'name': 'John', 'email': 'john@example.com'}}
421
422
# Marshal list
423
users_data = [
424
{'id': 1, 'name': 'John', 'email': 'john@example.com'},
425
{'id': 2, 'name': 'Jane', 'email': 'jane@example.com'}
426
]
427
marshalled_list = marshal(users_data, user_fields)
428
429
# Skip None values
430
data_with_none = {'id': 1, 'name': None, 'email': 'john@example.com'}
431
marshalled_skip_none = marshal(data_with_none, user_fields, skip_none=True)
432
# Result: {'id': 1, 'email': 'john@example.com'}
433
```
434
435
### Field Masking
436
437
```python
438
from flask_restplus import Api, Resource, fields, marshal_with
439
440
api = Api()
441
442
user_model = api.model('User', {
443
'id': fields.Integer,
444
'name': fields.String,
445
'email': fields.String,
446
'profile': fields.Nested({
447
'bio': fields.String,
448
'avatar_url': fields.String,
449
'preferences': fields.Nested({
450
'theme': fields.String,
451
'notifications': fields.Boolean
452
})
453
})
454
})
455
456
@api.route('/users/<int:user_id>')
457
class User(Resource):
458
@api.marshal_with(user_model)
459
def get(self, user_id):
460
# Client can request specific fields with ?mask= parameter
461
# Examples:
462
# ?mask=id,name - returns only id and name
463
# ?mask=id,name,profile{bio} - includes id, name, and profile.bio
464
# ?mask=profile{preferences{theme}} - nested field selection
465
466
user_data = {
467
'id': user_id,
468
'name': 'John Doe',
469
'email': 'john@example.com',
470
'profile': {
471
'bio': 'Software developer',
472
'avatar_url': 'http://example.com/avatar.jpg',
473
'preferences': {
474
'theme': 'dark',
475
'notifications': True
476
}
477
}
478
}
479
return user_data
480
```
481
482
### Ordered Models
483
484
```python
485
from flask_restplus import Api, fields, OrderedModel
486
487
api = Api()
488
489
# Regular model - field order not guaranteed
490
regular_model = api.model('Regular', {
491
'name': fields.String,
492
'id': fields.Integer,
493
'email': fields.String
494
})
495
496
# Ordered model - preserves field order
497
ordered_model = api.model('Ordered', OrderedModel('OrderedUser', {
498
'id': fields.Integer, # Will appear first
499
'name': fields.String, # Will appear second
500
'email': fields.String # Will appear third
501
}))
502
```
503
504
### Schema-based Models
505
506
```python
507
from flask_restplus import Api, SchemaModel
508
509
api = Api()
510
511
# JSON schema definition
512
user_schema = {
513
"type": "object",
514
"properties": {
515
"id": {"type": "integer"},
516
"name": {"type": "string"},
517
"email": {"type": "string", "format": "email"}
518
},
519
"required": ["id", "name"]
520
}
521
522
# Create model from JSON schema
523
user_model = api.model('User', SchemaModel('User', schema=user_schema))
524
```