0
# Fields
1
2
ODMantic field definitions provide MongoDB-specific options for model attributes, including indexing, validation, primary keys, and custom MongoDB field names.
3
4
## Capabilities
5
6
### Field Function
7
8
Define model fields with MongoDB-specific configuration options.
9
10
```python { .api }
11
def Field(
12
default=...,
13
*,
14
key_name=None,
15
primary_field=False,
16
index=False,
17
unique=False,
18
default_factory=None,
19
title=None,
20
description=None,
21
json_schema_extra=None,
22
const=None,
23
gt=None,
24
ge=None,
25
lt=None,
26
le=None,
27
multiple_of=None,
28
min_items=None,
29
max_items=None,
30
min_length=None,
31
max_length=None,
32
regex=None,
33
examples=None
34
):
35
"""
36
Define a model field with MongoDB-specific options.
37
38
Args:
39
default: Default value for the field (use ... for required fields)
40
key_name: MongoDB field name (different from Python attribute name)
41
primary_field: Mark this field as primary key (_id in MongoDB)
42
index: Create an index on this field
43
unique: Create a unique index on this field
44
default_factory: Callable that returns default value
45
title: Field title for schema
46
description: Field description for schema
47
json_schema_extra: Additional JSON schema data
48
const: Field must have this exact value
49
gt: Greater than constraint (numbers only)
50
ge: Greater than or equal constraint (numbers only)
51
lt: Less than constraint (numbers only)
52
le: Less than or equal constraint (numbers only)
53
multiple_of: Must be multiple of this value (numbers only)
54
min_items: Minimum items in sequence
55
max_items: Maximum items in sequence
56
min_length: Minimum string length
57
max_length: Maximum string length
58
regex: Regular expression pattern for strings
59
examples: Example values for schema
60
61
Returns:
62
Field configuration for use in model definition
63
"""
64
```
65
66
### FieldProxy
67
68
Proxy objects for building queries against model fields.
69
70
```python { .api }
71
class FieldProxy:
72
"""Proxy for model fields enabling query building."""
73
74
def __eq__(self, other):
75
"""Equality comparison for queries."""
76
77
def __ne__(self, other):
78
"""Not equal comparison for queries."""
79
80
def __gt__(self, other):
81
"""Greater than comparison for queries."""
82
83
def __ge__(self, other):
84
"""Greater than or equal comparison for queries."""
85
86
def __lt__(self, other):
87
"""Less than comparison for queries."""
88
89
def __le__(self, other):
90
"""Less than or equal comparison for queries."""
91
```
92
93
## Usage Examples
94
95
### Basic Field Definitions
96
97
```python
98
from odmantic import Model, Field
99
from typing import Optional
100
from datetime import datetime
101
102
class User(Model):
103
# Required field with no default
104
name: str
105
106
# Field with default value
107
is_active: bool = True
108
109
# Field with validation constraints
110
age: int = Field(ge=0, le=150, description="User age in years")
111
112
# Field with unique constraint
113
email: str = Field(unique=True, description="User email address")
114
115
# Field with default factory
116
created_at: datetime = Field(default_factory=datetime.utcnow)
117
118
# Optional field
119
bio: Optional[str] = Field(None, max_length=500)
120
```
121
122
### Custom MongoDB Field Names
123
124
```python
125
class Product(Model):
126
name: str
127
# Python attribute is 'price_usd' but stored as 'price' in MongoDB
128
price_usd: float = Field(key_name="price", gt=0)
129
130
# Python attribute is 'desc' but stored as 'description' in MongoDB
131
desc: str = Field(key_name="description", max_length=1000)
132
```
133
134
### Primary Key Fields
135
136
```python
137
from odmantic import ObjectId
138
import uuid
139
140
# Default ObjectId primary key (automatic)
141
class DefaultPrimary(Model):
142
name: str
143
# id: ObjectId field is automatically created
144
145
# Custom primary key
146
class CustomPrimary(Model):
147
custom_id: str = Field(primary_field=True, default_factory=lambda: str(uuid.uuid4()))
148
name: str
149
# This model uses custom_id as _id in MongoDB
150
151
# ObjectId primary key with custom name
152
class NamedPrimary(Model):
153
user_id: ObjectId = Field(primary_field=True, default_factory=ObjectId)
154
name: str
155
```
156
157
### Index Fields
158
159
```python
160
class SearchableDocument(Model):
161
title: str = Field(index=True) # Regular index
162
slug: str = Field(unique=True) # Unique index
163
content: str
164
tags: list[str] = Field(index=True) # Index on array field
165
166
# Multiple fields with indexes
167
author: str = Field(index=True)
168
category: str = Field(index=True)
169
published_date: datetime = Field(default_factory=datetime.utcnow, index=True)
170
```
171
172
### Validation Fields
173
174
```python
175
from typing import List
176
import re
177
178
class ValidationExample(Model):
179
# String validation
180
username: str = Field(min_length=3, max_length=20, regex=r"^[a-zA-Z0-9_]+$")
181
182
# Numeric validation
183
score: float = Field(ge=0.0, le=100.0, multiple_of=0.1)
184
rating: int = Field(ge=1, le=5)
185
186
# List validation
187
tags: List[str] = Field(min_items=1, max_items=10)
188
189
# Constant value
190
version: str = Field(const="1.0")
191
192
# Example values for documentation
193
status: str = Field(examples=["active", "inactive", "pending"])
194
```
195
196
### Default Value Strategies
197
198
```python
199
from odmantic import Model, Field
200
from datetime import datetime
201
from uuid import uuid4
202
203
class DefaultExamples(Model):
204
# Static default
205
status: str = "pending"
206
207
# Default with Field()
208
priority: int = Field(default=1)
209
210
# Factory function for dynamic defaults
211
created_at: datetime = Field(default_factory=datetime.utcnow)
212
unique_code: str = Field(default_factory=lambda: str(uuid4()))
213
214
# Optional field with None default
215
notes: Optional[str] = Field(default=None)
216
217
# Required field (no default)
218
name: str = Field(...)
219
```
220
221
### Complex Field Examples
222
223
```python
224
from decimal import Decimal
225
from enum import Enum
226
227
class Status(str, Enum):
228
ACTIVE = "active"
229
INACTIVE = "inactive"
230
PENDING = "pending"
231
232
class ComplexModel(Model):
233
# Enum field
234
status: Status = Field(default=Status.PENDING)
235
236
# Decimal field with precision constraints
237
price: Decimal = Field(gt=0, max_digits=10, decimal_places=2)
238
239
# Nested dict with validation
240
metadata: dict[str, str] = Field(default_factory=dict)
241
242
# Complex validation with regex
243
phone: str = Field(regex=r"^\+?1?\d{9,15}$", description="Phone number in international format")
244
245
# List with item constraints
246
scores: List[int] = Field(default_factory=list, min_items=0, max_items=100)
247
```
248
249
### Field Queries
250
251
```python
252
# Fields automatically become FieldProxy objects for queries
253
class User(Model):
254
name: str = Field(index=True)
255
age: int = Field(ge=0)
256
email: str = Field(unique=True)
257
258
# Use fields in queries
259
from odmantic import AIOEngine
260
261
async def query_examples(engine: AIOEngine):
262
# Equality
263
users = await engine.find(User, User.name == "Alice")
264
265
# Comparison
266
adults = await engine.find(User, User.age >= 18)
267
young_adults = await engine.find(User, User.age >= 18, User.age < 30)
268
269
# String matching
270
gmail_users = await engine.find(User, User.email.match(r".*@gmail\.com"))
271
272
# Multiple conditions
273
active_adults = await engine.find(
274
User,
275
User.age >= 18,
276
User.name != "Admin"
277
)
278
```
279
280
### Advanced Field Configuration
281
282
```python
283
from pydantic import field_validator
284
285
class AdvancedModel(Model):
286
# Field with comprehensive configuration
287
name: str = Field(
288
min_length=2,
289
max_length=50,
290
description="Full name of the user",
291
examples=["John Doe", "Jane Smith"],
292
json_schema_extra={"pattern": "^[A-Za-z ]+$"}
293
)
294
295
# Custom validation with field_validator
296
email: str = Field(unique=True, description="User email address")
297
298
@field_validator('email')
299
@classmethod
300
def validate_email(cls, v):
301
if not v or '@' not in v:
302
raise ValueError('Invalid email format')
303
return v.lower().strip()
304
305
# Field with custom MongoDB name and validation
306
account_balance: float = Field(
307
key_name="balance",
308
ge=0.0,
309
description="Account balance in USD",
310
json_schema_extra={"multipleOf": 0.01}
311
)
312
```