jypi
  • Explore
ChatWays to LearnMind mapAbout

jypi

  • About Us
  • Our Mission
  • Team
  • Careers

Resources

  • Ways to Learn
  • Mind map
  • Blog
  • Help Center
  • Community Guidelines
  • Contributor Guide

Legal

  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Content Policy

Connect

  • Twitter
  • Discord
  • Instagram
  • Contact Us
jypi

© 2026 jypi. All rights reserved.

Fast API
Chapters

1Introduction to FastAPI

2Routing and Endpoints

3Request and Response Handling

4Dependency Injection

5Security and Authentication

6Database Integration

Setting Up a DatabaseSQLAlchemy IntegrationUsing Tortoise ORMAsynchronous Database ConnectionsCRUD OperationsDatabase MigrationsConnection PoolingHandling TransactionsDatabase TestingOptimizing Database Queries

7Testing FastAPI Applications

8Asynchronous Programming

9Deployment Strategies

10Real-world Applications and Projects

Courses/Fast API/Database Integration

Database Integration

11788 views

Connect and interact with databases efficiently using FastAPI to build data-driven applications.

Content

3 of 10

Using Tortoise ORM

Tortoise ORM: Async-Friendly, Sassy Guide
2524 views
intermediate
humorous
visual
software development
gpt-5-mini
2524 views

Versions:

Tortoise ORM: Async-Friendly, Sassy Guide

Watch & Learn

AI-discovered learning video

Sign in to watch the learning video for this topic.

Sign inSign up free

Start learning for free

Sign up to save progress, unlock study materials, and track your learning.

  • Bookmark content and pick up later
  • AI-generated study materials
  • Flashcards, timelines, and more
  • Progress tracking and certificates

Free to join · No credit card required

Using Tortoise ORM with FastAPI — The Async Desert Rose You Didn't Know You Needed

"If SQLAlchemy is the Swiss Army knife of ORMs, Tortoise is the lightweight espresso shot for async Python apps." — Your slightly caffeinated TA

You're already familiar with setting up databases and getting cozy with SQLAlchemy earlier in this course. Now we take the async-first lane: welcome to Tortoise ORM, a Django-like ORM built specifically for async frameworks like FastAPI. This isn't repeating setup basics — it's about choosing a tool that's naturally fluent in async, and gluing it to FastAPI in a secure, maintainable way (remember our Security and Authentication lessons? We'll integrate that mindset here).


Why Tortoise? Quick elevator pitch

  • Async-native: built for asyncio from the ground up — no threads pretending to be async.
  • Django-ish models: you'll feel right at home if you've used Django ORM.
  • Pydantic helpers: generates Pydantic models for fast endpoint wiring.
  • Lightweight and easier to pick up for simple-to-medium projects compared to the sprawling SQLAlchemy ecosystem.

But yes, SQLAlchemy remains powerful and flexible; Tortoise is a pragmatic alternative when async simplicity and developer speed are the priority.


First things first: install

pip install tortoise-orm
pip install aiofiles  # sometimes useful for async file ops in apps
pip install aerich   # optional, for migrations

(We covered how to pick DB backends in "Setting Up a Database" — Tortoise supports sqlite, postgres, mysql, etc. Use the same credentials and connection strings.)


Core concepts — the cheat sheet

  • Model classes inherit from tortoise.models.Model.
  • Fields are tortoise.fields like IntField, CharField, ForeignKeyField.
  • Use register_tortoise to attach Tortoise to FastAPI lifecycle events (startup/shutdown).
  • Generate Pydantic schemas with pydantic_model_creator.
  • Use Aerich for migrations.

Minimal FastAPI + Tortoise example (auth-ready)

This snippet shows how to register Tortoise, define a User model, make Pydantic schemas, and wire endpoints. It assumes you already learned how to secure endpoints; here we show a pattern to fetch the current user with a token and Tortoise queries.

from fastapi import FastAPI, Depends, HTTPException
from tortoise import fields
from tortoise.models import Model
from tortoise.contrib.fastapi import register_tortoise
from tortoise.contrib.pydantic import pydantic_model_creator

app = FastAPI()

class User(Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(50, unique=True)
    hashed_password = fields.CharField(128)
    is_active = fields.BooleanField(default=True)

# Auto-generate Pydantic schemas
User_Pydantic = pydantic_model_creator(User, name='User')
UserIn_Pydantic = pydantic_model_creator(User, name='UserIn', exclude_readonly=True)

# DB registration (hook into FastAPI startup/shutdown)
register_tortoise(
    app,
    db_url='sqlite://db.sqlite3',
    modules={'models': ['__main__']},
    generate_schemas=True,  # set False in prod and use migrations
    add_exception_handlers=True,
)

# Dependency to get current user (after you implement JWT retrieval in auth lessons)
async def get_current_user(token: str = Depends(/* your jwt dependency */)):
    user_id = /* decode token to id */
    user = await User.get_or_none(id=user_id)
    if not user or not user.is_active:
        raise HTTPException(status_code=401, detail='Unauthorized')
    return user

@app.post('/users', response_model=User_Pydantic)
async def create_user(user_in: UserIn_Pydantic):
    # do password hashing using passlib as in Security lessons
    user_obj = await User.create(**user_in.dict())
    return await User_Pydantic.from_tortoise_orm(user_obj)

@app.get('/me', response_model=User_Pydantic)
async def read_me(current_user=Depends(get_current_user)):
    return await User_Pydantic.from_tortoise_orm(current_user)

Notes:

  • We used register_tortoise to avoid manual startup/shutdown wiring; it's a convenience that calls Tortoise.init and Tortoise.close_connections for you.
  • generate_schemas=True is OK for prototyping, but use Aerich for controlled migrations in production.

Transactions, relationships, and querying — the essentials

  • Transactions: use in_transaction context manager.
from tortoise.transactions import in_transaction

async with in_transaction() as conn:
    await User.filter(...).using_db(conn).update(...)
    # ensures atomicity
  • Relationships behave like Django's. Use ForeignKeyField and ManyToManyField.
  • To avoid N+1 problems, use prefetch_related and select_related:
posts = await Author.filter(id=1).prefetch_related('posts')
  • For efficiency, fetch Pydantic directly from querysets: await User_Pydantic.from_queryset(User.filter(...))

Migrations with Aerich (recommended)

  1. pip install aerich
  2. Initialize: aerich init -t yourmodule.settings.TORTOISE_CONFIG
  3. aerich init-db for first time
  4. aerich migrate and aerich upgrade thereafter

Aerich stores migration history and lets you evolve schemas without generate_schemas=True.


Quick comparison: Tortoise vs SQLAlchemy (from earlier module)

Concern Tortoise SQLAlchemy
Async first ✅ built-in ✅ (async supported via async engines, more setup)
Learning curve Low Medium–High
Ecosystem Smaller, focused Huge, extensible
Migrations Aerich Alembic
Flexibility for complex queries Good for most Best for extreme edge cases

So if you enjoyed SQLAlchemy's power but felt setup-heavy, Tortoise is your fast-lane alternative for async apps.


Security integration checklist (connects to our Authentication module)

  1. Hash passwords with a proven lib (passlib's bcrypt/argon2) — never store plaintext.
  2. Use JWT or OAuth for tokens; decode in a dependency and fetch user with Tortoise.
  3. Check is_active, roles, or permissions in dependencies before returning data.
  4. Avoid leaking DB internals in error messages; add exception handlers.

Common gotchas & tips

  • Remember: everything is async. Use await like your life depends on it.
  • For prod with Postgres, prefer asyncpg as the driver.
  • generate_schemas=True is fine locally but don't rely on it in production.
  • If you need raw SQL, use await Tortoise.get_connection('default').execute_query('...').

Final mic drop — TL;DR and next steps

  • Tortoise ORM is a practical, async-first ORM that integrates cleanly with FastAPI.
  • Use register_tortoise for lifecycle wiring, pydantic_model_creator for quick schemas, and Aerich for migrations.
  • Tie it into your auth system by decoding tokens -> fetching user via Tortoise -> applying permission checks.

Big idea: choose the tool that matches the concurrency model of your app. If your app is async, using an async-native ORM is not just convenient — it prevents subtle performance and correctness issues.

Actionable next steps:

  1. Convert a small sample router from SQLAlchemy to Tortoise and compare developer ergonomics.
  2. Add Aerich to your repo and practice a migration cycle.
  3. Implement a secure login flow using your Security module and test it end-to-end.

Go build something asynchronous and slightly delightful. Your users (and your server) will thank you.

Flashcards
Mind Map
Speed Challenge

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Ready to practice?

Sign up now to study with flashcards, practice questions, and more — and track your progress on this topic.

Study with flashcards, timelines, and more
Earn certificates for completed courses
Bookmark content for later reference
Track your progress across all topics