0
# Framework Integration
1
2
Integration utilities and extensions for web frameworks, serialization libraries, and testing utilities. Tortoise ORM provides first-class support for popular Python web frameworks and tools, making it easy to integrate into existing applications.
3
4
## Capabilities
5
6
### FastAPI Integration
7
8
Seamless integration with FastAPI through middleware and utilities.
9
10
```python { .api }
11
from tortoise.contrib.fastapi import register_tortoise
12
13
def register_tortoise(
14
app,
15
config=None,
16
config_file=None,
17
db_url=None,
18
modules=None,
19
generate_schemas=False,
20
add_exception_handlers=False
21
):
22
"""
23
Register Tortoise ORM with FastAPI application.
24
25
Args:
26
app: FastAPI application instance
27
config (dict, optional): Tortoise configuration
28
config_file (str, optional): Path to config file
29
db_url (str, optional): Database URL
30
modules (dict, optional): Model modules
31
generate_schemas (bool): Auto-generate database schemas
32
add_exception_handlers (bool): Add ORM exception handlers
33
"""
34
35
def HTTPNotFoundError():
36
"""HTTP 404 exception for FastAPI."""
37
38
def register_tortoise_middlewares(app):
39
"""Register Tortoise middlewares with FastAPI app."""
40
```
41
42
### Pydantic Integration
43
44
Generate Pydantic models from Tortoise models for API serialization.
45
46
```python { .api }
47
from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
48
49
def pydantic_model_creator(
50
cls,
51
name=None,
52
exclude=(),
53
include=(),
54
computed=(),
55
allow_cycles=True,
56
sort_alphabetically=False,
57
exclude_readonly=False,
58
meta_override=None,
59
validators=None,
60
module=None
61
):
62
"""
63
Create Pydantic model from Tortoise model.
64
65
Args:
66
cls: Tortoise model class
67
name (str, optional): Name for Pydantic model
68
exclude (tuple): Fields to exclude
69
include (tuple): Fields to include (if specified, only these)
70
computed (tuple): Computed fields to include
71
allow_cycles (bool): Allow circular references
72
sort_alphabetically (bool): Sort fields alphabetically
73
exclude_readonly (bool): Exclude readonly fields
74
meta_override (dict, optional): Override Meta attributes
75
validators (dict, optional): Field validators
76
module (str, optional): Module name for the model
77
78
Returns:
79
Type[BaseModel]: Pydantic model class
80
"""
81
82
def pydantic_queryset_creator(
83
cls,
84
name=None,
85
exclude=(),
86
include=(),
87
computed=(),
88
allow_cycles=True,
89
sort_alphabetically=False
90
):
91
"""
92
Create Pydantic model for queryset serialization.
93
94
Args:
95
cls: Tortoise model class
96
name (str, optional): Name for Pydantic model
97
exclude (tuple): Fields to exclude
98
include (tuple): Fields to include
99
computed (tuple): Computed fields to include
100
allow_cycles (bool): Allow circular references
101
sort_alphabetically (bool): Sort fields alphabetically
102
103
Returns:
104
Type[BaseModel]: Pydantic model for lists
105
"""
106
```
107
108
### Testing Utilities
109
110
Testing helpers and database setup utilities for unit and integration tests.
111
112
```python { .api }
113
from tortoise.contrib.test import TestCase, TortoiseTestCase, initializer, finalizer
114
115
class TestCase:
116
"""Base test case with Tortoise ORM setup."""
117
pass
118
119
class TortoiseTestCase(TestCase):
120
"""Async test case with automatic Tortoise setup/teardown."""
121
122
async def asyncSetUp(self):
123
"""Setup method called before each test."""
124
125
async def asyncTearDown(self):
126
"""Teardown method called after each test."""
127
128
def initializer(modules, db_url=None, loop=None):
129
"""
130
Initialize Tortoise for testing.
131
132
Args:
133
modules (list): Model modules to load
134
db_url (str, optional): Database URL (defaults to in-memory SQLite)
135
loop: Event loop to use
136
"""
137
138
def finalizer():
139
"""Clean up Tortoise after testing."""
140
141
def getDBConfig(app_label="models", modules=None):
142
"""
143
Get database configuration for testing.
144
145
Args:
146
app_label (str): Application label
147
modules (list, optional): Model modules
148
149
Returns:
150
dict: Database configuration
151
"""
152
```
153
154
### Framework Middleware
155
156
Middleware integrations for various web frameworks.
157
158
#### Starlette/FastAPI Middleware
159
160
```python { .api }
161
from tortoise.contrib.starlette import register_tortoise
162
163
def register_tortoise(
164
app,
165
config=None,
166
config_file=None,
167
db_url=None,
168
modules=None,
169
generate_schemas=False
170
):
171
"""Register Tortoise with Starlette/FastAPI app."""
172
```
173
174
#### Sanic Integration
175
176
```python { .api }
177
from tortoise.contrib.sanic import register_tortoise
178
179
def register_tortoise(
180
app,
181
config=None,
182
config_file=None,
183
db_url=None,
184
modules=None,
185
generate_schemas=False
186
):
187
"""Register Tortoise with Sanic app."""
188
```
189
190
#### Quart Integration
191
192
```python { .api }
193
from tortoise.contrib.quart import register_tortoise
194
195
def register_tortoise(
196
app,
197
config=None,
198
config_file=None,
199
db_url=None,
200
modules=None,
201
generate_schemas=False
202
):
203
"""Register Tortoise with Quart app."""
204
```
205
206
#### aiohttp Integration
207
208
```python { .api }
209
from tortoise.contrib.aiohttp import register_tortoise
210
211
def register_tortoise(
212
app,
213
config=None,
214
config_file=None,
215
db_url=None,
216
modules=None,
217
generate_schemas=False
218
):
219
"""Register Tortoise with aiohttp app."""
220
```
221
222
#### BlackSheep Integration
223
224
```python { .api }
225
from tortoise.contrib.blacksheep import register_tortoise
226
227
def register_tortoise(
228
app,
229
config=None,
230
config_file=None,
231
db_url=None,
232
modules=None,
233
generate_schemas=False
234
):
235
"""Register Tortoise with BlackSheep app."""
236
```
237
238
### Database-Specific Extensions
239
240
Extensions providing database-specific functionality.
241
242
#### PostgreSQL Extensions
243
244
```python { .api }
245
from tortoise.contrib.postgres.fields import TSVectorField, ArrayField
246
from tortoise.contrib.postgres.functions import Random, ArrayAgg, JsonAgg
247
248
class TSVectorField:
249
"""PostgreSQL text search vector field."""
250
def __init__(self, **kwargs): ...
251
252
class ArrayField:
253
"""PostgreSQL array field."""
254
def __init__(self, element_type, size=None, **kwargs): ...
255
256
# PostgreSQL-specific functions
257
def Random(): ...
258
def ArrayAgg(field, distinct=False, ordering=None): ...
259
def JsonAgg(field, distinct=False, ordering=None): ...
260
```
261
262
#### MySQL Extensions
263
264
```python { .api }
265
from tortoise.contrib.mysql.fields import GeometryField
266
from tortoise.contrib.mysql.functions import GroupConcat, Rand
267
268
class GeometryField:
269
"""MySQL geometry field."""
270
def __init__(self, srid=4326, **kwargs): ...
271
272
# MySQL-specific functions
273
def GroupConcat(field, separator=',', distinct=False, order_by=None): ...
274
def Rand(): ...
275
```
276
277
## Usage Examples
278
279
### FastAPI Integration Example
280
281
```python
282
from fastapi import FastAPI
283
from tortoise.contrib.fastapi import register_tortoise
284
from tortoise.models import Model
285
from tortoise import fields
286
from tortoise.contrib.pydantic import pydantic_model_creator
287
288
# Define model
289
class User(Model):
290
id = fields.IntField(pk=True)
291
name = fields.CharField(max_length=50)
292
email = fields.CharField(max_length=100, unique=True)
293
294
class Meta:
295
table = "users"
296
297
# Create Pydantic models
298
User_Pydantic = pydantic_model_creator(User, name="User")
299
UserIn_Pydantic = pydantic_model_creator(User, name="UserIn", exclude_readonly=True)
300
301
# FastAPI app
302
app = FastAPI()
303
304
# Register Tortoise
305
register_tortoise(
306
app,
307
db_url="sqlite://db.sqlite3",
308
modules={"models": ["__main__"]},
309
generate_schemas=True,
310
add_exception_handlers=True,
311
)
312
313
@app.post("/users/", response_model=User_Pydantic)
314
async def create_user(user: UserIn_Pydantic):
315
user_obj = await User.create(**user.dict(exclude_unset=True))
316
return await User_Pydantic.from_tortoise_orm(user_obj)
317
318
@app.get("/users/{user_id}", response_model=User_Pydantic)
319
async def get_user(user_id: int):
320
return await User_Pydantic.from_tortoise_orm(
321
await User.get(id=user_id)
322
)
323
```
324
325
### Pydantic Model Generation
326
327
```python
328
from tortoise.contrib.pydantic import pydantic_model_creator
329
from tortoise.models import Model
330
from tortoise import fields
331
332
class Post(Model):
333
id = fields.IntField(pk=True)
334
title = fields.CharField(max_length=100)
335
content = fields.TextField()
336
author = fields.ForeignKeyField("models.User", related_name="posts")
337
created_at = fields.DatetimeField(auto_now_add=True)
338
339
# Create different Pydantic models for different use cases
340
PostIn = pydantic_model_creator(
341
Post,
342
name="PostIn",
343
exclude_readonly=True, # Exclude id, created_at
344
exclude=("author",) # Exclude author for input
345
)
346
347
PostOut = pydantic_model_creator(
348
Post,
349
name="PostOut",
350
include=("id", "title", "created_at", "author.name") # Include author name
351
)
352
353
PostList = pydantic_queryset_creator(Post, name="PostList")
354
355
# Usage in API
356
@app.post("/posts/", response_model=PostOut)
357
async def create_post(post_data: PostIn, current_user: User):
358
post = await Post.create(**post_data.dict(), author=current_user)
359
return await PostOut.from_tortoise_orm(post)
360
```
361
362
### Testing Setup
363
364
```python
365
from tortoise.contrib.test import TestCase
366
from tortoise.contrib.test import initializer, finalizer
367
import asyncio
368
369
class UserTestCase(TestCase):
370
async def asyncSetUp(self):
371
# Set up test data
372
self.user = await User.create(
373
name="Test User",
374
email="test@example.com"
375
)
376
377
async def test_user_creation(self):
378
user = await User.create(
379
name="Alice",
380
email="alice@example.com"
381
)
382
self.assertEqual(user.name, "Alice")
383
self.assertEqual(user.email, "alice@example.com")
384
385
async def test_user_query(self):
386
users = await User.filter(name__contains="Test").all()
387
self.assertEqual(len(users), 1)
388
self.assertEqual(users[0].name, "Test User")
389
390
# Manual test setup
391
async def test_setup():
392
await initializer(["app.models"])
393
394
# Run tests
395
try:
396
# Test code here
397
user = await User.create(name="Test", email="test@example.com")
398
assert user.name == "Test"
399
finally:
400
await finalizer()
401
402
# Run test
403
asyncio.run(test_setup())
404
```
405
406
### Multiple Framework Integration
407
408
```python
409
# Sanic example
410
from sanic import Sanic
411
from tortoise.contrib.sanic import register_tortoise
412
413
app = Sanic("MyApp")
414
415
register_tortoise(
416
app,
417
db_url="postgres://user:pass@localhost/db",
418
modules={"models": ["app.models"]},
419
generate_schemas=True
420
)
421
422
# Quart example
423
from quart import Quart
424
from tortoise.contrib.quart import register_tortoise
425
426
app = Quart(__name__)
427
428
register_tortoise(
429
app,
430
config={
431
'connections': {
432
'default': 'sqlite://db.sqlite3'
433
},
434
'apps': {
435
'models': {
436
'models': ['app.models'],
437
'default_connection': 'default',
438
}
439
}
440
}
441
)
442
```
443
444
### Database-Specific Features
445
446
```python
447
# PostgreSQL array field
448
from tortoise.contrib.postgres.fields import ArrayField
449
from tortoise.contrib.postgres.functions import ArrayAgg
450
451
class Article(Model):
452
id = fields.IntField(pk=True)
453
title = fields.CharField(max_length=200)
454
tags = ArrayField(fields.CharField(max_length=50))
455
456
# Query with array functions
457
articles_with_tags = await Article.annotate(
458
all_tags=ArrayAgg('tags')
459
).all()
460
461
# MySQL geometry field
462
from tortoise.contrib.mysql.fields import GeometryField
463
464
class Location(Model):
465
id = fields.IntField(pk=True)
466
name = fields.CharField(max_length=100)
467
coordinates = GeometryField()
468
```
469
470
### Custom Middleware
471
472
```python
473
from starlette.middleware.base import BaseHTTPMiddleware
474
from tortoise import connections
475
476
class DatabaseMiddleware(BaseHTTPMiddleware):
477
async def dispatch(self, request, call_next):
478
# Custom database logic before request
479
response = await call_next(request)
480
# Custom database logic after request
481
return response
482
483
# Add to FastAPI
484
app.add_middleware(DatabaseMiddleware)
485
```
486
487
### Error Handling Integration
488
489
```python
490
from fastapi import HTTPException
491
from tortoise.exceptions import DoesNotExist, IntegrityError
492
493
@app.exception_handler(DoesNotExist)
494
async def does_not_exist_handler(request, exc):
495
raise HTTPException(status_code=404, detail="Resource not found")
496
497
@app.exception_handler(IntegrityError)
498
async def integrity_error_handler(request, exc):
499
raise HTTPException(status_code=400, detail="Data integrity violation")
500
```