Featured image of post Tortoise ORM In a Nutshell

Tortoise ORM In a Nutshell

Python Tortoise ORM In a Nutshell

Introduction

Tortoise ORM is like that chill friend who handles all your database interactions while you focus on writing awesome Python code.

It’s an asynchronous ORM (Object-Relational Mapper) that plays nicely with async frameworks like FastAPI, Starlette, and even the rebel asyncio.

So if you’ve ever dreamed of making database queries without blocking your app’s event loop, Tortoise ORM is here to make that dream come true. 🐢✨

Why Use Tortoise ORM?

  • Asynchronous Support – No more blocking operations. Your app stays fast and responsive.
  • Simple API – Tortoise ORM keeps things clean and Pythonic.
  • Built-in Schema Generation – No need to manually create tables.
  • Works with Pydantic – Plays well with FastAPI and data validation.
  • Supports Multiple Databases – PostgreSQL, MySQL, SQLite, and even MariaDB.

Setting Up Tortoise ORM

Before you go full ninja with Tortoise ORM, you need to install it. So fire up your terminal and run:

1
pip install tortoise-orm

If you’re planning to use it with PostgreSQL or MySQL, don’t forget to install the corresponding database driver:

1
2
pip install asyncpg  # For PostgreSQL
pip install aiomysql  # For MySQL

Basic Usage

Let’s build a simple model with Tortoise ORM. Imagine we have a blog, and we need a Post model.

Defining a Model

1
2
3
4
5
6
7
from tortoise import fields, Tortoise, models

class Post(models.Model):
    id = fields.IntField(pk=True)
    title = fields.CharField(max_length=255)
    content = fields.TextField()
    created_at = fields.DatetimeField(auto_now_add=True)

Initializing Tortoise ORM

Before using the ORM, we need to initialize it with a database configuration.

1
2
3
4
5
6
7
8
import asyncio

async def init():
    await Tortoise.init(
        db_url="sqlite://db.sqlite3",
        modules={"models": ["__main__"]}  # Points to the module where our models are defined
    )
    await Tortoise.generate_schemas()

Creating and Fetching Data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
async def create_post():
    post = await Post.create(title="Hello World", content="This is my first post!")
    print(f"Post Created: {post.title}")

async def get_posts():
    posts = await Post.all()
    for post in posts:
        print(post.title)

async def main():
    await init()
    await create_post()
    await get_posts()

asyncio.run(main())

Boom! 🎉 You just created a database record asynchronously.

Querying Data

Filtering Records

1
2
post = await Post.filter(title="Hello World").first()
print(post.content)

Updating Records

1
2
3
post = await Post.get(id=1)
post.title = "Updated Title"
await post.save()

Deleting Records

1
2
post = await Post.get(id=1)
await post.delete()

Comparison Table: Tortoise ORM vs Other ORMs

FeatureTortoise ORMSQLAlchemyDjango ORM
Async Support✅ Yes✅ Yes (with asyncio)❌ No
Schema Generation✅ Yes❌ No✅ Yes
Database SupportPostgreSQL, MySQL, SQLiteManyPostgreSQL, MySQL, SQLite
Ease of Use✅ Simple API🔧 Complex🔥 Easy
Pydantic Support✅ Yes❌ No❌ No

Running Migrations

Tortoise ORM doesn’t have built-in migrations (yet), but you can use Aerich, which is a migration tool built for Tortoise.

Install it with:

1
pip install aerich

Initialize it:

1
aerich init -t config.TORTOISE_ORM

Create and apply migrations:

1
2
aerich migrate
aerich upgrade

Key Ideas

Key IdeaSummary
What is Tortoise ORM?An async ORM for Python with simple API
Why use it?Asynchronous, lightweight, schema generation
How to install?pip install tortoise-orm
Basic usage?Define models, init ORM, create/fetch data
How to query?Use .filter(), .get(), .all() methods
How to update/delete?Modify and call .save() / .delete()
Comparison to other ORMs?Async support, schema gen, ease of use
Migrations?Use Aerich for migrations

References