Changelogs » Tortoise-orm



.. warning::
**This release drops support of Python 3.5:**

Tortoise ORM now requires a minimum of CPython 3.6 or PyPy3.6-7.1

New Features:
- Fetching records from the DB is now up to 25% faster.


Breaking Changes:
- The hash used to make generated indexes unique has changed.
The old algorithm had a very high chance of collisions,
the new hash algorithm is much better in this regard.


- Fixed the ``_FieldMeta`` class not to checking if the 1st base class was Field, so would break with mixins.
- The ``Field`` class now calls ``super().__init__``, so mixins are properly initialised.


- Names ForeignKey constraints in a consistent way


- Fields can have 2nd base class which makes IDEs know python type (str, int, datetime...) of the field.
- The ``type`` parameter of ``Field.__init__`` is removed, instead we use the 2nd base class
- Foreign keys and indexes are now defined correctly in MySQL so that they take effect as expected
- MySQL now doesn't warn of unsafe index creation anymore


- Fixed bug in schema creation for MySQL where non-int PK did not get declared properly (195)


- ``iexact`` filter modifier was implemented. Queries like ``«queryset».filter(name__iexact=...)`` will perform case-insensitive search.


- Fix minor bug in ``Model.__init__`` where we raise the wrong error on setting RFK/M2M values directly.
- Fields in ``Queryset.values_list()`` is now in the defined Model order.
- Fields in ``Queryset.values()`` is now in the defined Model order.


- Sample Starlette integration
- Relational fields are now lazily constructed via properties instead of in the constructor,
this results in a significant overhead reduction for Model instantiation with many relationships.


- Assigning to the FK field will correctly set the associated db-field
- Reading a nullalble FK field can now be None
- Nullalble FK fields reverse-FK is now also nullable
- Deleting a nullable FK field sets it to None


- Fixed installing Tortoise-ORM in non-unicode systems. (180)
- ``«queryset».update(…)`` now correctly uses the DB-specific ``to_db_value()``
- ``fetch_related(…)`` now correctly encodes non-integer keys.
- ``ForeignKey`` fields of type ``UUIDField`` are now escaped consistently.
- Pre-generated ForeignKey fields (e.g. UUIDField) is now checked for persistence correctly.
- Duplicate M2M ``.add(…)`` now checks using consistent field encoding.
- ``source_field`` Fields are now handled correctly for ordering.
- ``source_field`` Fields are now handled correctly for updating.


* Security fixes for ``«model».save()`` & ``«model».delete()``:

This is now fully parametrized, and these operations are no longer susceptible to escaping issues.

* Performance improvements:

- Simple update is now ~3-6× faster
- Partial update is now ~3× faster
- Delete is now ~2.7x faster

- Fix generated Schema Primary Key for ``BigIntField`` for MySQL and PostgreSQL.
- Added support for using a ``SmallIntField`` as a auto-gen Primary Key.
- Ensure that default PK is added to the top of the attrs.


* Model schema now has a discovery API:

One can call ``Tortoise.describe_models()`` or ``Tortoise.describe_model(<Model>)`` to get
a full description of the model(s).

Please see :meth:`tortoise.Tortoise.describe_model` and :meth:`tortoise.Tortoise.describe_models` for more info.

- Fix in generating comments for Foreign Keys in ``MySQL``
- Added schema support for PostgreSQL. Either set  ``"schema": "custom"`` var in ``credentials`` or as a query parameter ``?schema=custom``
- Default MySQL charset to ``utf8mb4``. If a charset is provided it will also force the TABLE charset to the same.


.. warning::
**This release brings with it, deprecation of Python 3.5:**

We will increase the minimum supported version of Python to 3.6,
as 3.5 is reaching end-of-life,
and is missing many useful features for async applications.

We will discontinue Python 3.5 support on the next major release (Likely 0.14.0)

New Features:
- Example Sanic integration along with register_tortoise hook in contrib (163)
- ``.values()`` and ``.values_list()`` now default to all fields if none are specified.
- ``generate_schema()`` now generates well-formatted DDL SQL statements.
- Added ``TruncationTestCase`` testing class that truncates tables to allow faster testing of transactions.
- Partial saves are now supported (157): ``['model','field','names'])``

- Fixed state leak between database drivers which could cause incorrect DDL generation.
- Fixed missing table/column comment generation for ``ForeignKeyField`` and ``ManyToManyField``
- Fixed comment generation to escape properly for ``SQLite``
- Fixed comment generation for ``PostgreSQL`` to not duplicate comments
- Fixed generation of schema for fields that defined custom ``source_field`` values defined
- Fixed working with Models that have fields with custom ``source_field`` values defined
- Fixed safe creation of M2M tables for MySQL dialect (168)

- Examples have been reworked:

- Simplified init of many examples
- Re-did ```` example
- A new ```` example (turned into test case)

- Lots of small documentation cleanups


- Support connecting to PostgreSQL via Unix domain socket (simple case).
- Self-referential Foreign and Many-to-Many keys are now allowed


* Handle a ``__models__`` variable within modules to override the model discovery mechanism.

If you define the ``__models__`` variable in ``yourapp.models`` (or wherever you specify to load your models from),
``generate_schema()`` will use that list, rather than automatically finding all models for you.

- Split model consructor into from-Python and from-DB paths, leading to 15-25% speedup for large fetch operations.
- More efficient queryset manipulation, 5-30% speedup for small fetches.


- Using non registered models or wrong references causes an ConfigurationError with a helpful message.


- Inherit fields from Mixins, together with abstract model classes.


- Added description attribute to Field class. (124)
- Added the ability to leverage field description from (124) to generate table column comments and ability to add table level comments


- Fix accidental double order-by for ``.values()`` based queries. (143)


* Bulk insert operation:

.. note::
The bulk insert operation will do the minimum to ensure that the object
created in the DB has all the defaults and generated fields set,
this may result in incomplete references in Python.

e.g. ``IntField`` primary keys will not be populated.

This is recommend only for throw away inserts where you want to ensure optimal
insert performance.

.. code-block:: python3

User(name="...", email="..."),
User(name="...", email="...")

- Notable efficiency improvement for regular inserts


* Tortoise ORM now supports non-autonumber primary keys.

.. note::
This is a big feature change. It should not break any existing implementations.

That primary key will be accesible through a reserved field ``pk`` which will be an alias of whichever field has been nominated as a primary key.
That alias field can be used as a field name when doing filtering e.g. ``.filter(pk=...)`` etc…

We currently support single (non-composite) primary keys of any indexable field type, but only these field types are recommended:

.. code-block:: python3


One must define a primary key by setting a ``pk`` parameter to ``True``.

If you don't define a primary key, we will create a primary key of type ``IntField`` with name of ``id`` for you.

Any of these are valid primary key definitions in a Model:

.. code-block:: python3

id = fields.IntField(pk=True)

checksum = fields.CharField(pk=True)

guid = fields.UUIDField(pk=True)


- Fixed connection retry to work with transactions
- Added broader PostgreSQL connection failiure detection


- Added automatic PostgreSQL connection retry


- Extra parameters now get passed through to the MySQL & PostgreSQL drivers


- Fixed SQLite handling of DatetimeField


- Code has been reformatted using ``black``, and minor code cleanups (120 123)
- Sample Quart integration (121)
- Better isolation of connection handling — Allows more dynamic connections so we can do pooling & reconnections.
- Added automatic MySQL connection retry


- Fixed ``.count()`` when a join happens (109)


- Fixed ``unique_together`` for foreign keys (114)
- Fixed Field.to_db_value method to handle Enum (113 115 116)


- Added ability to use ``unique_together`` meta Model option


- Fixed concurrency isolation when attempting to do multiple concurrent operations on a single connection.


- Fixed several convenience issues with foreign relations:

- FIXED: ``.all()`` actually returns the _query property as was documented.
- New models with FK don't automatically fail to resolve any data. They can now be evaluated lazily.

- Some DB's don't support OFFSET without Limit, added caps to signal workaround, which is to automatically add limit of 1000000
- Pylint plugin to know about default ``related_name`` for ForeignKey fields.
- Simplified capabilities to be static, and defined at class level.


* Added basic DB driver Capabilities.

Test runner now has the ability to skip tests conditionally, based on the DB driver Capabilities:

.. code-block:: python3

async def test_run_sqlite_only(self):

* Added per-field indexes.

When setting ``index=True`` on a field, Tortoise will now generate an index for it.

.. note::
Due to MySQL limitation of not supporting conditional index creation,
if ``safe=True`` (the default) is set, it won't create the index and emit a warning about it.

We plan to work around this limitation in a future release.

- Performance fix with PyPika for small fetch queries
- Remove parameter hack now that PyPika support Parametrized queries
- Fix typos in JSONField docstring
- Added ``.explain()`` method on ``QuerySet``.
- Add ``required`` read-only property to fields


- Added "safe" schema generation
- Correctly convert values to their db representation when using the "in" filter
- Added some common missing field types:

- ``BigIntField``
- ``TimeDeltaField``

- ``BigIntField`` can also be used as a primary key field.


- Test class isolation fixes & contextvars update
- Turned on autocommit for MySQL
- db_url now supports defaults and casting parameters to the right types


- Added ``.exclude()`` method for QuerySet
- Q objects can now be negated for ``NOT`` query (``~Q(...)``)
- Support subclassing on existing fields
- Numerous bug fixes
- Removed known broken connection pooling


- Pre-build some query & filters statically, 15-30% speed up for smaller queries.
- Required field params are now positional, so Python and IDE linters will pick up on it easier.
- Filtering also applies DB-specific transforms, Fixes 62
- Fixed recursion error on m2m management with big lists


- Refactor ``Tortoise.init()`` and test runner to not re-create connections per test, so now tests pass when using an SQLite in-memory database
- Can pass event loop to test initializer function: ``initializer(loop=loop)``
- Fix relative URI for SQLite
- Better error message for invalid filter param.
- Better error messages for missing/bad field params.
- ``nose2`` plugin
- Test utilities compatible with ``py.test``


- Uses macros on SQLite driver to minimise syncronisation. ``aiosqlite>=0.7.0``
- Uses prepared statements for insert, large insert performance increase.
- Pre-generate base pypika query object per model, providing general purpose speedup.


- Performance fixes from ``pypika>=0.15.6``
- Significant reduction in object creation time


- Fixed SQLite relative db path and :memory: now also works
- Removed confusing error message for missing db driver dependency
- Added ``aiosqlite`` as a required dependency
- ``execute_script()`` now annotates errors just like ``execute_query()``, to reduce confusion
- Bumped ``aiosqlite>=0.6.0`` for performance fix
- Added ``tortoise.run_async()`` helper function to make smaller scripts easier to run. It cleans up connections automatically.
- SQLite does autocommit by default.


- Fixed atomic decorator to get connection only on function call


- Fixed pre-init queryset objects creation


- Added support for running separate transactions in multidb config


- Changed default app label from 'models' to None
- Fixed ConfigurationError message for wrong connection name


- Set single_connection to True by default, as there is known issues with conection pooling
- Updated documentation


- Fixed M2M manager methods to correctly work with transactions
- Fixed mutating of queryset on select queries


* Refactored ``Tortoise.init()`` to init all connections and discover models from config passed
as argument.

.. caution::
This is a breaking change.

You no longer need to import the models module for discovery,
instead you need to provide an app ⇒ modules map with the init call:

.. code-block:: python3

async def init():
Here we create a SQLite DB using file "db.sqlite3"
also specify the app name of "models"
which contain models from "app.models"
await Tortoise.init(
modules={'models': ['app.models']}
Generate the schema
await Tortoise.generate_schemas()

For more info, please have a look at :ref:`init_app`

- New ``transactions`` module for implicit working with transactions
- Test frameworks overhauled:
- Better performance for test runner, using transactions to keep tests isolated.
- Now depends on an ``initializer()`` and ``finalizer()`` to set up and tear down DB state.
- Exceptions have been further clarified
- Support for CPython 3.7
- Added support for MySQL/MariaDB


- No more asserts, only Tortoise Exceptions
- Fixed PyLint plugin to work with pylint>=2.0.0
- Formalised unittest classes & documented them.
- ``__slots__`` where it was easy to do. (Changes class instances from dicts into tuples, memory savings)


- Fixed backward incompatibility for Python 3.7


- ``JSONField`` is now promoted to a standard field.
- Fixed ``DecimalField`` and ``BooleanField`` to work as expected on SQLite.
- Added ``FloatField``.
- Minimum supported version of PostgreSQL is 9.4
- Added ``.get(...)`` shortcut on query set.
- ``values()`` and ``values_list()`` now converts field values to python types


- Fixed ``through`` parameter honouring for ``ManyToManyField``


* Added support for nested queries for ``values`` and ``values_list``:

.. code-block:: python3

result = await Event.filter('id', 'name', tournament='tournament__name')
result = await Event.filter('id', 'participants__name')

- Fixed ``DatetimeField`` and ``DateField`` to work as expected on SQLite.
- Added ``PyLint`` plugin.
- Added test class to mange DB state for testing isolation.


- Added PostgreSQL ``JSONField``


- Added ``.annotate()`` method and basic aggregation funcs


- Added ``Prefetch`` object


- Added ``contains`` and other filter modifiers.
- Field kwarg ``default`` now accepts functions.


- Immutable QuerySet. ``unique`` flag for fields


* Added schema generation and more options for fields:

.. code-block:: python3

from tortoise import Tortoise
from tortoise.backends.sqlite.client import SqliteClient
from tortoise.utils import generate_schema

client = SqliteClient(db_name)
await client.create_connection()
await generate_schema(client)


* Added filtering and ordering by related models fields:

.. code-block:: python3

await Tournament.filter(
events__name__in=['1', '3']