0
# Models
1
2
ODMantic models define the structure and validation for MongoDB documents using Pydantic. Models provide type safety, data validation, and automatic serialization/deserialization between Python objects and MongoDB documents.
3
4
## Capabilities
5
6
### Model Base Class
7
8
Base class for MongoDB document models with full Pydantic integration.
9
10
```python { .api }
11
class Model:
12
"""Base class for MongoDB document models."""
13
14
# Class attributes
15
__collection__: str # MongoDB collection name (auto-generated from class name)
16
__config__: ODMConfigDict # Model configuration
17
18
def model_copy(self, *, include=None, exclude=None, update=None, deep=False):
19
"""
20
Create a copy of the model with optional changes.
21
22
Args:
23
include: Fields to include in the copy
24
exclude: Fields to exclude from the copy
25
update: Dictionary of field updates to apply
26
deep: Whether to make a deep copy
27
28
Returns:
29
New model instance with changes applied
30
"""
31
32
def copy(self, *, include=None, exclude=None, update=None, deep=False):
33
"""
34
Create a copy of the model (deprecated, use model_copy).
35
36
Args:
37
include: Fields to include in the copy
38
exclude: Fields to exclude from the copy
39
update: Dictionary of field updates to apply
40
deep: Whether to make a deep copy
41
42
Returns:
43
New model instance with changes applied
44
"""
45
46
def model_update(self, **kwargs):
47
"""
48
Update model instance in place with new values.
49
50
Args:
51
**kwargs: Field names and new values
52
53
Returns:
54
Self for method chaining
55
"""
56
57
def update(self, **kwargs):
58
"""
59
Update model instance in place (deprecated, use model_update).
60
61
Args:
62
**kwargs: Field names and new values
63
64
Returns:
65
Self for method chaining
66
"""
67
68
def model_dump_doc(self, *, include=None, exclude=None, by_alias=False,
69
exclude_unset=False, exclude_defaults=False, exclude_none=False):
70
"""
71
Convert model to MongoDB document dictionary.
72
73
Args:
74
include: Fields to include in output
75
exclude: Fields to exclude from output
76
by_alias: Use field aliases if defined
77
exclude_unset: Exclude fields that haven't been set
78
exclude_defaults: Exclude fields set to their default values
79
exclude_none: Exclude fields set to None
80
81
Returns:
82
dict: MongoDB document representation
83
"""
84
85
def doc(self, include=None):
86
"""
87
Convert to MongoDB document (deprecated, use model_dump_doc).
88
89
Args:
90
include: Fields to include in output
91
92
Returns:
93
dict: MongoDB document representation
94
"""
95
96
@classmethod
97
def model_validate_doc(cls, raw_doc):
98
"""
99
Parse MongoDB document into model instance.
100
101
Args:
102
raw_doc: Raw MongoDB document dictionary
103
104
Returns:
105
Model instance parsed from document
106
107
Raises:
108
DocumentParsingError: If parsing fails
109
"""
110
111
@classmethod
112
def parse_doc(cls, raw_doc):
113
"""
114
Parse MongoDB document (deprecated, use model_validate_doc).
115
116
Args:
117
raw_doc: Raw MongoDB document dictionary
118
119
Returns:
120
Model instance parsed from document
121
"""
122
```
123
124
### EmbeddedModel Base Class
125
126
Base class for embedded documents that can be nested within other models.
127
128
```python { .api }
129
class EmbeddedModel:
130
"""Base class for embedded documents."""
131
132
def model_update(self, **kwargs):
133
"""
134
Update embedded model instance in place with new values.
135
136
Args:
137
**kwargs: Field names and new values
138
139
Returns:
140
Self for method chaining
141
"""
142
143
def update(self, **kwargs):
144
"""
145
Update embedded model instance (deprecated, use model_update).
146
147
Args:
148
**kwargs: Field names and new values
149
150
Returns:
151
Self for method chaining
152
"""
153
```
154
155
### Configuration
156
157
```python { .api }
158
class ODMConfigDict(ConfigDict):
159
"""Configuration dictionary for ODM models."""
160
161
collection: str | None # Custom collection name
162
parse_doc_with_default_factories: bool # Use default factories when parsing
163
indexes: Callable[[], Iterable[Index | IndexModel]] | None # Additional indexes
164
165
# Pydantic options (selected subset)
166
title: str | None
167
json_schema_extra: dict | None
168
str_strip_whitespace: bool
169
arbitrary_types_allowed: bool
170
extra: Literal["allow", "forbid", "ignore"] | None
171
```
172
173
## Usage Examples
174
175
### Basic Model Definition
176
177
```python
178
from odmantic import Model, Field
179
from typing import Optional
180
from datetime import datetime
181
182
class User(Model):
183
name: str
184
email: str = Field(unique=True)
185
age: int = Field(ge=0, le=150)
186
created_at: datetime = Field(default_factory=datetime.utcnow)
187
is_active: bool = True
188
tags: Optional[list[str]] = None
189
190
# Custom collection name (optional)
191
class Config:
192
collection = "users"
193
```
194
195
### Model with Custom Configuration
196
197
```python
198
from odmantic import Model
199
from odmantic.config import ODMConfigDict
200
201
class Product(Model):
202
name: str
203
price: float = Field(gt=0)
204
description: Optional[str] = None
205
206
model_config = ODMConfigDict(
207
collection="products",
208
extra="forbid" # Don't allow extra fields
209
)
210
```
211
212
### Embedded Models
213
214
```python
215
from odmantic import Model, EmbeddedModel
216
217
class Address(EmbeddedModel):
218
street: str
219
city: str
220
country: str
221
zip_code: str
222
223
class Person(Model):
224
name: str
225
address: Address
226
work_address: Optional[Address] = None
227
228
# Usage
229
address = Address(
230
street="123 Main St",
231
city="New York",
232
country="USA",
233
zip_code="10001"
234
)
235
236
person = Person(name="John Doe", address=address)
237
```
238
239
### Model Operations
240
241
```python
242
# Create instance
243
user = User(
244
name="Alice Smith",
245
email="alice@example.com",
246
age=30,
247
tags=["developer", "python"]
248
)
249
250
# Copy with changes
251
updated_user = user.model_copy(update={"age": 31})
252
253
# Update in place
254
user.model_update(age=32, is_active=False)
255
256
# Convert to MongoDB document
257
doc = user.model_dump_doc()
258
print(doc) # {'_id': ObjectId(...), 'name': 'Alice Smith', ...}
259
260
# Parse from MongoDB document
261
raw_doc = {
262
'_id': ObjectId('...'),
263
'name': 'Bob Jones',
264
'email': 'bob@example.com',
265
'age': 25,
266
'created_at': datetime.utcnow(),
267
'is_active': True
268
}
269
user = User.model_validate_doc(raw_doc)
270
```
271
272
### Model with Relationships
273
274
```python
275
from odmantic import Model, Reference, ObjectId
276
277
class Author(Model):
278
name: str
279
email: str
280
281
class Book(Model):
282
title: str
283
author_id: ObjectId = Reference()
284
published_year: int
285
286
# You can define a property to load the related author
287
# (This would require custom implementation with the engine)
288
289
# Usage
290
author = Author(name="Jane Doe", email="jane@example.com")
291
book = Book(
292
title="Python Patterns",
293
author_id=author.id,
294
published_year=2023
295
)
296
```
297
298
### Model Validation
299
300
```python
301
from pydantic import validator, field_validator
302
303
class User(Model):
304
name: str
305
email: str
306
age: int
307
308
@field_validator('email')
309
@classmethod
310
def validate_email(cls, v):
311
if '@' not in v:
312
raise ValueError('Invalid email format')
313
return v.lower()
314
315
@field_validator('name')
316
@classmethod
317
def validate_name(cls, v):
318
if len(v.strip()) < 2:
319
raise ValueError('Name must be at least 2 characters')
320
return v.strip().title()
321
322
# This will raise validation errors for invalid data
323
try:
324
user = User(name="A", email="invalid", age=25)
325
except ValidationError as e:
326
print(e.errors())
327
```
328
329
### Model with Custom Primary Key
330
331
```python
332
from odmantic import Model, Field
333
import uuid
334
335
class CustomIdModel(Model):
336
custom_id: str = Field(primary_field=True, default_factory=lambda: str(uuid.uuid4()))
337
name: str
338
value: int
339
340
# The custom_id field will be stored as _id in MongoDB
341
model = CustomIdModel(name="test", value=42)
342
print(model.custom_id) # Auto-generated UUID string
343
```
344
345
### Model Configuration Options
346
347
```python
348
from odmantic import Model
349
from odmantic.config import ODMConfigDict
350
351
class ConfiguredModel(Model):
352
name: str
353
secret_field: str
354
355
model_config = ODMConfigDict(
356
# MongoDB collection name
357
collection="my_collection",
358
359
# Extra fields behavior: "allow", "forbid", "ignore"
360
extra="forbid",
361
362
# Validate field assignments
363
validate_assignment=True,
364
365
# Use enum values instead of names
366
use_enum_values=True,
367
368
# Allow population by field name and alias
369
populate_by_name=True
370
)
371
```