============
Tortoise ORM
============
.. image:: https://img.shields.io/pypi/v/tortoise-plus.svg?style=flat
:target: https://pypi.python.org/pypi/tortoise-plus
.. image:: https://pepy.tech/badge/tortoise-plus/month
:target: https://pepy.tech/project/tortoise-plus
.. image:: https://github.com/tortoise/tortoise-plus/workflows/gh-pages/badge.svg
:target: https://github.com/tortoise/tortoise-plus/actions?query=workflow:gh-pages
.. image:: https://github.com/tortoise/tortoise-plus/actions/workflows/ci.yml/badge.svg?branch=develop
:target: https://github.com/tortoise/tortoise-plus/actions?query=workflow:ci
.. image:: https://coveralls.io/repos/github/tortoise/tortoise-plus/badge.svg
:target: https://coveralls.io/github/tortoise/tortoise-plus
.. image:: https://app.codacy.com/project/badge/Grade/844030d0cb8240d6af92c71bfac764ff
:target: https://www.codacy.com/gh/tortoise/tortoise-plus/dashboard?utm_source=github.com&utm_medium=referral&utm_content=tortoise/tortoise-plus&utm_campaign=Badge_Grade
Introduction
============
Tortoise ORM is an easy-to-use ``asyncio`` ORM *(Object Relational Mapper)* inspired by Django.
You can find the docs at `Documentation <https://tortoise.github.io>`_
.. note::
Tortoise ORM is a young project and breaking changes are to be expected.
We keep a `Changelog <https://tortoise.github.io/CHANGELOG.html>`_ and it will have possible breakage clearly documented.
Tortoise ORM supports CPython 3.9 and later for SQLite, MySQL, PostgreSQL, Microsoft SQL Server, and Oracle.
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 <https://github.com/tortoise/orm-benchmarks>`_, where we measure different read and write operations (rows/sec, more is better), it's trading places with Pony ORM:
.. image:: https://raw.githubusercontent.com/tortoise/tortoise-plus/develop/docs/ORM_Perf.png
:target: https://github.com/tortoise/orm-benchmarks
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.
Getting Started
===============
Installation
------------
The following table shows the available installation options for different databases (note that there are multiple options of clients for some databases):
.. list-table:: Available Installation Options
:header-rows: 1
:widths: 30 70
* - Database
- Installation Command
* - SQLite
- ``pip install tortoise-plus``
* - PostgreSQL (psycopg)
- ``pip install tortoise-plus[psycopg]``
* - PostgreSQL (asyncpg)
- ``pip install tortoise-plus[asyncpg]``
* - MySQL (aiomysql)
- ``pip install tortoise-plus[aiomysql]``
* - MySQL (asyncmy)
- ``pip install tortoise-plus[asyncmy]``
* - MS SQL
- ``pip install tortoise-plus[asyncodbc]``
* - Oracle
- ``pip install tortoise-plus[asyncodbc]``
Quick Tutorial
--------------
Define the models by inheriting from ``tortoise.models.Model``.
.. code-block:: python3
from tortoise.models import Model
from tortoise import fields
class Tournament(Model):
id = fields.IntField(primary_key=True)
name = fields.CharField(max_length=20)
class Event(Model):
id = fields.BigIntField(primary_key=True)
name = fields.TextField()
tournament = fields.ForeignKeyField('models.Tournament', related_name='events', on_delete=fields.OnDelete.CASCADE)
participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team', on_delete=fields.OnDelete.SET_NULL)
class Team(Model):
id = fields.UUIDField(primary_key=True)
name = fields.CharField(max_length=20, unique=True)
After defining the models, Tortoise ORM needs to be initialized to establish the relationships between models and connect to the database.
The code below creates a connection to a SQLite DB database with the ``aiosqlite`` client. ``generate_schema`` sets up schema on an empty database.
``generate_schema`` is for development purposes only, check out ``aerich`` or other migration tools for production use.
.. code-block:: python3
from tortoise import Tortoise, run_async
async def init():
# Here we connect to a SQLite DB file.
# also specify the app name of "models"
# which contain models from "app.models"
await Tortoise.init(
db_url='sqlite://db.sqlite3',
modules={'models': ['app.models']}
)
# Generate the schema
await Tortoise.generate_schemas()
run_async(main())
``run_async`` is a helper function to run simple Tortoise scripts. Check out `Documentation <https://tortoise.github.io>`_ for FastAPI, Sanic and other integrations.
With the Tortoise initialized, the models are available for use:
.. code-block:: python3
async def main():
await Tortoise.init(
db_url='sqlite://db.sqlite3',
modules={'models': ['app.models']}
)
await Tortoise.generate_schemas()
# Creating an instance with .save()
tournament = Tournament(name='New Tournament')
await tournament.save()
# Or with .create()
await Event.create(name='Without participants', tournament=tournament)
event = await Event.create(name='Test', tournament=tournament)
participants = []
for i in range(2):
team = await Team.create(name='Team {}'.format(i + 1))
participants.append(team)
# Many to Many Relationship management is quite straightforward
# (there are .remove(...) and .clear() too)
await event.participants.add(*participants)
# Iterate over related entities with the async context manager
async for team in event.participants:
print(team.name)
# The related entities are cached and can be iterated in the synchronous way afterwards
for team in event.participants:
pass
# Use prefetch_related to fetch related objects
selected_events = await Event.filter(
participants=participants[0].id
).prefetch_related('participants', 'tournament')
for event in selected_events:
print(event.tournament.name)
print([t.name for t in event.participants])
# Prefetch multiple levels of related entities
await Team.all().prefetch_related('events__tournament')
# Filter and order by related models too
await Tournament.filter(
events__name__in=['Test', 'Prod']
).order_by('-events__participants__name').distinct()
run_async(main())
Learn more at the `documentation site <https://tortoise.github.io>`_
Migration
=========
Tortoise ORM uses `Aerich <https://github.com/tortoise/aerich>`_ as its database migration tool, see more detail at its `docs <https://github.com/tortoise/aerich>`_.
Contributing
============
Please have a look at the `Contribution Guide <docs/CONTRIBUTING.rst>`_.
ThanksTo
========
Powerful Python IDE `Pycharm <https://www.jetbrains.com/pycharm/>`_
from `Jetbrains <https://jb.gg/OpenSourceSupport>`_.
.. image:: https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg
:target: https://jb.gg/OpenSourceSupport
License
=======
This project is licensed under the Apache License - see the `LICENSE.txt <LICENSE.txt>`_ file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "tortoise-plus",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "sql, mysql, postgres, psql, sqlite, aiosqlite, asyncpg, relational, database, rdbms, orm, object mapper, async, asyncio, aio, psycopg",
"author": "tianqing",
"author_email": "tianqing108@126.com",
"download_url": "https://files.pythonhosted.org/packages/56/29/8e8151b9b257ef47d75fbc047a9496a05dffab2196b49893e135aff2f5e7/tortoise_plus-0.2.0.tar.gz",
"platform": null,
"description": "============\nTortoise ORM\n============\n\n.. image:: https://img.shields.io/pypi/v/tortoise-plus.svg?style=flat\n :target: https://pypi.python.org/pypi/tortoise-plus\n.. image:: https://pepy.tech/badge/tortoise-plus/month\n :target: https://pepy.tech/project/tortoise-plus\n.. image:: https://github.com/tortoise/tortoise-plus/workflows/gh-pages/badge.svg\n :target: https://github.com/tortoise/tortoise-plus/actions?query=workflow:gh-pages\n.. image:: https://github.com/tortoise/tortoise-plus/actions/workflows/ci.yml/badge.svg?branch=develop\n :target: https://github.com/tortoise/tortoise-plus/actions?query=workflow:ci\n.. image:: https://coveralls.io/repos/github/tortoise/tortoise-plus/badge.svg\n :target: https://coveralls.io/github/tortoise/tortoise-plus\n.. image:: https://app.codacy.com/project/badge/Grade/844030d0cb8240d6af92c71bfac764ff\n :target: https://www.codacy.com/gh/tortoise/tortoise-plus/dashboard?utm_source=github.com&utm_medium=referral&utm_content=tortoise/tortoise-plus&utm_campaign=Badge_Grade\n\nIntroduction\n============\n\nTortoise ORM is an easy-to-use ``asyncio`` ORM *(Object Relational Mapper)* inspired by Django.\n\nYou can find the docs at `Documentation <https://tortoise.github.io>`_\n\n.. note::\n Tortoise ORM is a young project and breaking changes are to be expected.\n We keep a `Changelog <https://tortoise.github.io/CHANGELOG.html>`_ and it will have possible breakage clearly documented.\n\nTortoise ORM supports CPython 3.9 and later for SQLite, MySQL, PostgreSQL, Microsoft SQL Server, and Oracle.\n\nWhy was Tortoise ORM built?\n---------------------------\n\nTortoise ORM was built to provide a lightweight, async-native Object-Relational Mapper for Python with a familiar Django-like API.\n\nTortoise ORM performs well when compared to other Python ORMs. In `our benchmarks <https://github.com/tortoise/orm-benchmarks>`_, where we measure different read and write operations (rows/sec, more is better), it's trading places with Pony ORM:\n\n.. image:: https://raw.githubusercontent.com/tortoise/tortoise-plus/develop/docs/ORM_Perf.png\n :target: https://github.com/tortoise/orm-benchmarks\n\nHow is an ORM useful?\n---------------------\n\nAn Object-Relational Mapper (ORM) abstracts database interactions, allowing developers to work with databases using high-level, object-oriented code instead of raw SQL.\n\n* Reduces boilerplate SQL, allowing faster development with cleaner, more readable code.\n* Helps prevent SQL injection by using parameterized queries.\n* Centralized schema and relationship definitions make code easier to manage and modify.\n* Handles schema changes through version-controlled migrations.\n\nGetting Started\n===============\n\nInstallation\n------------\n\nThe following table shows the available installation options for different databases (note that there are multiple options of clients for some databases):\n\n.. list-table:: Available Installation Options\n :header-rows: 1\n :widths: 30 70\n\n * - Database\n - Installation Command\n * - SQLite\n - ``pip install tortoise-plus``\n * - PostgreSQL (psycopg)\n - ``pip install tortoise-plus[psycopg]``\n * - PostgreSQL (asyncpg)\n - ``pip install tortoise-plus[asyncpg]``\n * - MySQL (aiomysql)\n - ``pip install tortoise-plus[aiomysql]``\n * - MySQL (asyncmy)\n - ``pip install tortoise-plus[asyncmy]``\n * - MS SQL\n - ``pip install tortoise-plus[asyncodbc]``\n * - Oracle\n - ``pip install tortoise-plus[asyncodbc]``\n\n\nQuick Tutorial\n--------------\n\nDefine the models by inheriting from ``tortoise.models.Model``.\n\n\n.. code-block:: python3\n\n from tortoise.models import Model\n from tortoise import fields\n\n class Tournament(Model):\n id = fields.IntField(primary_key=True)\n name = fields.CharField(max_length=20)\n\n\n class Event(Model):\n id = fields.BigIntField(primary_key=True)\n name = fields.TextField()\n tournament = fields.ForeignKeyField('models.Tournament', related_name='events', on_delete=fields.OnDelete.CASCADE)\n participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team', on_delete=fields.OnDelete.SET_NULL)\n\n\n class Team(Model):\n id = fields.UUIDField(primary_key=True)\n name = fields.CharField(max_length=20, unique=True)\n\n\nAfter defining the models, Tortoise ORM needs to be initialized to establish the relationships between models and connect to the database.\nThe code below creates a connection to a SQLite DB database with the ``aiosqlite`` client. ``generate_schema`` sets up schema on an empty database.\n``generate_schema`` is for development purposes only, check out ``aerich`` or other migration tools for production use.\n\n.. code-block:: python3\n\n from tortoise import Tortoise, run_async\n\n async def init():\n # Here we connect to a SQLite DB file.\n # also specify the app name of \"models\"\n # which contain models from \"app.models\"\n await Tortoise.init(\n db_url='sqlite://db.sqlite3',\n modules={'models': ['app.models']}\n )\n # Generate the schema\n await Tortoise.generate_schemas()\n\n run_async(main())\n\n``run_async`` is a helper function to run simple Tortoise scripts. Check out `Documentation <https://tortoise.github.io>`_ for FastAPI, Sanic and other integrations.\n\nWith the Tortoise initialized, the models are available for use:\n\n.. code-block:: python3\n\n async def main():\n await Tortoise.init(\n db_url='sqlite://db.sqlite3',\n modules={'models': ['app.models']}\n )\n await Tortoise.generate_schemas()\n\n # Creating an instance with .save()\n tournament = Tournament(name='New Tournament')\n await tournament.save()\n\n # Or with .create()\n await Event.create(name='Without participants', tournament=tournament)\n event = await Event.create(name='Test', tournament=tournament)\n participants = []\n for i in range(2):\n team = await Team.create(name='Team {}'.format(i + 1))\n participants.append(team)\n\n # Many to Many Relationship management is quite straightforward\n # (there are .remove(...) and .clear() too)\n await event.participants.add(*participants)\n\n # Iterate over related entities with the async context manager\n async for team in event.participants:\n print(team.name)\n\n # The related entities are cached and can be iterated in the synchronous way afterwards\n for team in event.participants:\n pass\n\n # Use prefetch_related to fetch related objects\n selected_events = await Event.filter(\n participants=participants[0].id\n ).prefetch_related('participants', 'tournament')\n for event in selected_events:\n print(event.tournament.name)\n print([t.name for t in event.participants])\n\n # Prefetch multiple levels of related entities\n await Team.all().prefetch_related('events__tournament')\n\n # Filter and order by related models too\n await Tournament.filter(\n events__name__in=['Test', 'Prod']\n ).order_by('-events__participants__name').distinct()\n\n run_async(main())\n\n\nLearn more at the `documentation site <https://tortoise.github.io>`_\n\n\nMigration\n=========\n\nTortoise ORM uses `Aerich <https://github.com/tortoise/aerich>`_ as its database migration tool, see more detail at its `docs <https://github.com/tortoise/aerich>`_.\n\nContributing\n============\n\nPlease have a look at the `Contribution Guide <docs/CONTRIBUTING.rst>`_.\n\nThanksTo\n========\n\nPowerful Python IDE `Pycharm <https://www.jetbrains.com/pycharm/>`_\nfrom `Jetbrains <https://jb.gg/OpenSourceSupport>`_.\n\n.. image:: https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg\n :target: https://jb.gg/OpenSourceSupport\n\nLicense\n=======\n\nThis project is licensed under the Apache License - see the `LICENSE.txt <LICENSE.txt>`_ file for details.\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "add sqlcipher support",
"version": "0.2.0",
"project_urls": {
"Documentation": "https://tortoise-plus.readthedocs.io",
"Homepage": "https://github.com/tortoise/tortoise-plus",
"Repository": "https://github.com/tortoise/tortoise-plus.git"
},
"split_keywords": [
"sql",
" mysql",
" postgres",
" psql",
" sqlite",
" aiosqlite",
" asyncpg",
" relational",
" database",
" rdbms",
" orm",
" object mapper",
" async",
" asyncio",
" aio",
" psycopg"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b0d5b5946cae21b1515955b0b62c16bc4b7104f9059e9b3dbbb141356faca4e3",
"md5": "c15ab12cc38014f2d9e20a7187517fb6",
"sha256": "11460ae313f627b8858c003a485131863ba63fdc06cf281af5a3a86f23321cff"
},
"downloads": -1,
"filename": "tortoise_plus-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c15ab12cc38014f2d9e20a7187517fb6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 174555,
"upload_time": "2025-07-12T04:54:02",
"upload_time_iso_8601": "2025-07-12T04:54:02.502263Z",
"url": "https://files.pythonhosted.org/packages/b0/d5/b5946cae21b1515955b0b62c16bc4b7104f9059e9b3dbbb141356faca4e3/tortoise_plus-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "56298e8151b9b257ef47d75fbc047a9496a05dffab2196b49893e135aff2f5e7",
"md5": "314880436bfa47b1ccc484e704213c1c",
"sha256": "2aae09e10960de2e88ac9bf47e99ed2ee84ef39394025be0d1f75fc22ed6a718"
},
"downloads": -1,
"filename": "tortoise_plus-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "314880436bfa47b1ccc484e704213c1c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 129789,
"upload_time": "2025-07-12T04:54:04",
"upload_time_iso_8601": "2025-07-12T04:54:04.478758Z",
"url": "https://files.pythonhosted.org/packages/56/29/8e8151b9b257ef47d75fbc047a9496a05dffab2196b49893e135aff2f5e7/tortoise_plus-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-12 04:54:04",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tortoise",
"github_project": "tortoise-plus",
"github_not_found": true,
"lcname": "tortoise-plus"
}