or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

database.mdexceptions.mdfunctions.mdindex.mdintegration.mdmodels.mdquerying.mdsignals.mdtransactions.mdvalidators.md

integration.mddocs/

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

```