Tortoise ORM¶
Tortoise ORM is an easy-to-use asyncio
ORM (Object Relational Mapper) inspired by Django.
Note
Tortoise ORM is a young project and breaking changes are to be expected. We keep a Changelog and it will have possible breakage clearly documented.
Source & issue trackers are available at https://github.com/tortoise/tortoise-orm/
Tortoise ORM supports CPython 3.9 and later for SQLite, MySQL, PostgreSQL, Microsoft SQL Server, and Oracle.
Introduction¶
Why was Tortoise ORM built?¶
Python has many existing and mature ORMs, unfortunately they are designed with an opposing paradigm of how I/O gets processed.
asyncio
is relatively new technology that has a different concurrency model, and the largest change is regarding how I/O is handled.
However, Tortoise ORM is not first attempt of building asyncio
ORM, there are many cases of developers attempting to map synchronous python ORMs to the async world, initial attempts did not have a clean API.
Hence we started Tortoise ORM.
Tortoise ORM is designed to be functional, yet familiar, to ease the migration of developers wishing to switch to asyncio
.
It also performs well when compared to other Python ORMs. In our benchmarks, where we measure different read and write operations (rows/sec, more is better), it’s trading places with Pony ORM:

How is an ORM useful?¶
An Object-Relational Mapper (ORM) abstracts database interactions, allowing developers to work with databases using high-level, object-oriented code instead of raw SQL.
Reduces boilerplate SQL, allowing faster development with cleaner, more readable code.
Helps prevent SQL injection by using parameterized queries.
Centralized schema and relationship definitions make code easier to manage and modify.
Handles schema changes through version-controlled migrations.
Features¶
Clean, familiar Python interface¶
Model definitions:
from tortoise.models import Model
from tortoise import fields
class Tournament(Model):
id = fields.IntField(primary_key=True)
name = fields.TextField()
Operations on models, queries and complex aggregations:
# Creating a record
await Tournament.create(name='Another Tournament')
# Searching for a record
tour = await Tournament.filter(name__contains='Another').first()
print(tour.name)
# Count groups of records with a complex condition
await Tournament.annotate(
name_prefix=Case(
When(name__startswith="One", then="1"),
When(name__startswith="Two", then="2"),
default="0",
),
).annotate(
count=Count(F("name_prefix")),
).group_by(
"name_prefix"
).values("name_prefix", "count")
See Getting started for a more detailed guide.
Pluggable Database backends¶
Tortoise ORM currently supports the following Databases:
PostgreSQL >= 9.4 (using
asyncpg
)SQLite (using
aiosqlite
)MySQL/MariaDB (using asyncmy)
Microsoft SQL Server/Oracle (using
asyncodbc
)
And more¶
Tortoise ORM supports the following features:
Composable, Django-inspired Models
Supports relations, such as
ForeignKeyField
andManyToManyField
Supports many standard Fields
Comprehensive Query API
Transactions Transactions
Supports tests frameworks, see UnitTest support
If you want to contribute, check out issues first, and then create a PR.