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?

Tortoise ORM was built to provide a lightweight, async-native Object-Relational Mapper for Python with a familiar Django-like API.

Tortoise ORM 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:

_images/ORM_Perf.png

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:

If you want to contribute, check out issues first, and then create a PR.