.. rst-class:: emphasize-children
default
for not None
on pydantic model creationF
expression work with QuerySet.filter()
.py.typed
in source distribution.datetime
parsing from int
for fields.DatetimeField
.get_or_create
passes the using_db=
on if provided.loop
and connection_class
parameters to be passed on to asyncpg.tortoise-orm
now installs with no C-dependencies, if you want to use the C accelerators, please do a pip install tortoise-orm[accel]
instead.<instance>.clone()
method that will create a cloned instance in memory. To persist it you still need to call .save()
.clone()
will raise a ParamsError
if tortoise can't generate a primary key. In that case do a .clone(pk=<newval>)
None
and the primary key can be automatically generated, this will create a new record. We however still recommend the .clone()
method instead..save()
can be forced to do a create by setting force_create=True
.save()
can be forced to do an update by setting force_update=True
update_fields
for a .save()
operation will strongly prefer to do an update if possibleField.default
effect on db level when generate tableJSONField
typed in pydantic_model_creator
.sql()
method on QuerySet
sqlite://:memory:
in Windows thrown OSError: [WinError 123]
bulk_create()
insertion of records with overridden primary key when the primary key is DB-generatedqueryset.exists()
and Model.exists()
.Model[<pkval>]
that will return the object or raise KeyError
basestring
.group_by()
with join nowF
expression in .save()
nowIntEnumField
accept valid int value and CharEnumField
accept valid str valueexclude_raw_fields=True
as it is a critically important field__contains
for non-text fields (e.g. JSONB
)Q
expression to function with _filter
parameter on aggregations.group_by()
supportGROUP BY
class is missing for an aggregate with a specified order.TruncationTestCase
now properly quotes table names when it clears them out.app_label
to test initializer(...)
and TORTOISE_TEST_APP
as test environment variable.Warning
This is a security fix release. We recommend everyone update.
contains
, starts_with
or ends_with
filters (and their case-insensitive counterparts)contains
, starts_with
or ends_with
filters (and their case-insensitive counterparts)Added support for partial models:
To create a partial model, one can do a .only(<fieldnames-as-strings>)
as part of the QuerySet.
This will create model instances that only have those values fetched.
Persisting changes on the model is allowed only when:
<model>.save(update_fields=[...])
.only(...)
To protect against common mistakes we ensure that errors get raised:
AttributeError
.<model>.save()
a IncompleteInstanceError
will be raised as the model is, as requested, incomplete.<model>.save(update_fields=[...])
and you didn't include the primary key in the .only(...)
,
then IncompleteInstanceError
will be raised indicating that updates can't be done without the primary key being known.<model>.save(update_fields=[...])
and one of the fields in update_fields
was not in the .only(...)
,
then IncompleteInstanceError
as that field is not available to be updated..values()
query over a Foreign KeyTortoise.describe_model(<MODEL>, ...)
to <MODEL>.describe(...)
Tortoise.describe_model()
generate_schemas
param being ignored in tortoise.contrib.quart.register_tortoise
F
funtions wrapped forgetting about distinct=True
var IN ()
SQL generated using __in=
and __not_in
filters.values()
& values_list()
now includes annotations.values()
& values_list()
GROUP BY
precedes HAVING
to ensure that filtering by aggregates work correctly.BooleanField
values correctly on SQLite & MySQLQuerySetSingle
now has better code completion
Created Pydantic models will now have the basic validation elements:
required
is correctly populated for required fieldsnullable
is added to the schema where nulls are acceptedmaxLength
for CharFieldsminimum
& maximum
values for integer fieldsTo get Pydantic to handle nullable/default fields correctly one should do a **user.dict(exclude_unset=True)
when passing values to a Model class.
Added FastAPI
helper that is based on the starlette
helper but optionally adds helpers to catch and report with proper error DoesNotExist
and IntegrityError
Tortoise exceptions.
Allows a Pydantic model to exclude all read-only fields by setting exclude_readonly=True
when calling pydantic_model_creator
.
a Tortoise PydanticModel
now provides two extra helper functions:
from_queryset
: Returns a List[PydanticModel]
which is the format that e.g. FastAPI expectsfrom_queryset_single
: allows one to avoid calling await
multiple times to get the object and all its related items.Caution!
This release drops support for Python 3.6:
Tortoise ORM now requires a minimum of CPython 3.7
Model docstrings and #:
comments directly preceding Field definitions are now used as docstrings and DDL descriptions.
This is now cleaned and carried as part of the docstring
parameter in describe_model(...)
If one doesn't explicitly specify a Field description=
or Model Meta.table_description=
then we default to the first line as the description.
This is done because a description is submitted to the DB, and needs to be short (depending on DB, 63 chars) in size.
Usage example:
class Something(Model):
"""
A Docstring.
Some extra info.
"""
# A regular comment
name = fields.CharField(max_length=50)
#: A docstring comment
chars = fields.CharField(max_length=50, description="Some chars")
#: A docstring comment
#: Some more detail
blip = fields.CharField(max_length=50)
# When looking at the describe model:
{
"description": "A Docstring.",
"docstring": "A Docstring.\n\nSome extra info.",
...
"data_fields": [
{
"name": "name",
...
"description": null,
"docstring": null
},
{
"name": "chars",
...
"description": "Some chars",
"docstring": "A docstring comment"
},
{
"name": "blip",
...
"description": "A docstring comment",
"docstring": "A docstring comment\nSome more detail"
}
]
}
Early Partial Init of models.
We now have an early init of models, which can be useful when needing Models that are not bound to a DB, but otherwise complete. e.g. Schema generation without needing to be properly set up.
Usage example:
# Lets say you defined your models in "some/models.py", and "other/ddef.py"
# And you are going to use them in the "model" namespace:
Tortoise.init_models(["some.models", "other.ddef"], "models")
# Now the models will have relationships built, so introspection of schema will be comprehensive
Pydantic serialisation.
We now include native support for automatically building a Pydantic model from Tortoise ORM models. This will correctly model:
At this stage we only suport serialisation, not deserialisation.
For mode information, please see :ref:`contrib_pydantic`
F
expressions to in annotations. (#301)limit(...)
and offset(...)
raise ParamsError
. (#306)queryset.update()
. (#308)distinct
flag to Aggregate (#312)JSONField
Removed tortoise.aggregation
as this was deprecated since 0.14.0
Removed start_transaction
as it has been broken since 0.15.0
Removed support for Python 3.6 / PyPy-3.6, as it has been broken since 0.15.0
If you still need Python 3.6 support, you can install tortoise-orm<0.16
as we will still backport critical bugfixes to the 0.15 branch for a while.
.. rst-class:: emphasize-children
GROUP BY
class is missing for an aggregate with a specified order.contains
, starts_with
or ends_with
filters (and their case-insensitive counterparts)contains
, starts_with
or ends_with
filters (and their case-insensitive counterparts)generate_schemas
param being ignored in tortoise.contrib.quart.register_tortoise
var IN ()
SQL generated using __in=
and __not_in
filters.values()
& values_list()
now includes annotations.values()
& values_list()
GROUP BY
precedes HAVING
to ensure that filtering by aggregates work correctly.BooleanField
values correctly on SQLite & MySQLsource_field
option. (#311)IntegrityError
with unique field and get_or_create
get_or_none(...)
, classmethod of Model
class, works in the same way as queryset
get_or_none(...)
now raises MultipleObjectsReturned
if multiple object fetched. (#298)to_field=
parameter for FK/O2O to a non-PK but still uniquely indexed remote field. (#287)queryset.update()
- This allows for atomic updates of data in the database. (#294)range
filter to support between and
syntaxordering
option for model Meta
class to apply default orderingTextField
now recommends usage of CharField
if wanting unique indexing instead of just saying "indexing not supported".count()
now honours offset and limitForeignKeyField
as a boolean expression will automatically resolve as False
if it is NoneForeignKeyField
won't touch the DB if it is None
QuerySet.Update()
now returns the count of the no of rows affected. Note, thatQuerySet.Delete()
now returns the count of the no of rows deleted.db_connection.execute_query()
now returns rows_affected, results
. (This is informational only)get_or_none(...)
as syntactic sugar for filter(...).first()
BinaryField
for storing binary objects (bytes
).TextField
to use LONGTEXT
for MySQL to allow for larger than 64KB of text.index=true
and as part of indexes
TextField
is marked as deprecated.
We can't guarnatee that it will be properly indexed or unique in all cases.related_name=False
Refactored Fields:
Fields have been refactored, for better maintenance. There should be no change for most users.
describe_model()
now returns the DB type, and dialect overrides.JSONField
will now automatically use python-rapidjson
as an accelerator if it is available.DecimalField
and aggregations on it, now behaves much more like expected on SQLite (#256)RuntimeWarning
when a module has no models to import (#254)Added OneToOneField
implementation:
OneToOneField
describes a one to one relation between two models.
It can be set from the primary side only, but resolved from both sides in the same way.
describe_model(...)
now also reports OneToOne relations in both directions.
Usage example:
event: fields.OneToOneRelation[Event] = fields.OneToOneField(
"models.Event", on_delete=fields.CASCADE, related_name="address"
)
auto_now_add
argument of DatetimeField
is handled correctly in the SQLite backend.unique_together
now creates named constrains, to prevent the DB from auto-assigning a potentially non-unique constraint name.auto_now
field doesn't replace the filter value with now()
anymore.Q()
correctly (#240)minsize
and maxsize
connection parametersDateField
& DatetimeField
deserializes faster on PostgreSQL & MySQL..values()
to do less copying, resulting in a slight speedup.Q()
objects as parameters to Q()
objects simultaneously.indexes
will correctly map the foreign key if referenced by name.start_transaction
is deprecated, please use @atomic()
or async with in_transaction():
instead.
This release brings with it, deprecation of Python 3.6 / PyPy-3.6:
This is due to small differences with how the backported aiocontextvars
behaves
in comparison to the built-in in Python 3.7+.
There is a known context confusion, specifically regarding nested transactions.
.. rst-class:: emphasize-children
alias
is now no longer reserved.ManyToManyField
is now a function that has the type of the relation for autocomplete,
this allows for better type hinting at less effort.Caution!
This release drops support of Python 3.5:
Tortoise ORM now requires a minimum of CPython 3.6 or PyPy3.6-7.1
Trim()
, Length()
, Coalesce()
, Lower()
, Upper()
added to tortoise.functions module.Queryset.values()
and Queryset.values_list()
expressions.await
-able as long as one didn't populate it via .prefetch_related()
Meta:
class using indexes
. It works just like unique_toghether
.UNIQUE
statements.KEY
statements.unique_together
will correctly map the foreign key if referenced by name.import from tortoise.aggregation
is deprecated, please do import from tortoise.functions
instead... rst-class:: emphasize-children
Field
class now calls super().__init__
, so mixins are properly initialised."
as it was causing issues on Python 3.6._FieldMeta
class not to checking if the 1st base class was Field, so would break with mixins.Field
class now calls super().__init__
, so mixins are properly initialised.type
parameter of Field.__init__
is removed, instead we use the 2nd base classiexact
filter modifier was implemented. Queries like «queryset».filter(name__iexact=...)
will perform case-insensitive search.Model.__init__
where we raise the wrong error on setting RFK/M2M values directly.Queryset.values_list()
is now in the defined Model order.Queryset.values()
is now in the defined Model order.«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..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:
BigIntField
for MySQL and PostgreSQL.SmallIntField
as a auto-gen Primary Key.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.
MySQL
"schema": "custom"
var in credentials
or as a query parameter ?schema=custom
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)
.values()
and .values_list()
now default to all fields if none are specified.generate_schema()
now generates well-formatted DDL SQL statements.TruncationTestCase
testing class that truncates tables to allow faster testing of transactions.obj.save(update_fields=['model','field','names'])
ForeignKeyField
and ManyToManyField
SQLite
PostgreSQL
to not duplicate commentssource_field
values definedsource_field
values definedgenerate_schema.py
examplerelations_recirsive.py
example (turned into test case).. rst-class:: emphasize-children
Handle a __models__
variable within modules to override the model discovery mechanism.
If you define the
__models__
variable inyourapp.models
(or wherever you specify to load your models from),generate_schema()
will use that list, rather than automatically finding all models for you.
.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.
User.bulk_create([
User(name="...", email="..."),
User(name="...", email="...")
])
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:
IntField
BigIntField
CharField
UUIDField
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:
id = fields.IntField(pk=True)
checksum = fields.CharField(pk=True)
guid = fields.UUIDField(pk=True)
.. rst-class:: emphasize-children
black
, and minor code cleanups (#120 #123).count()
when a join happens (#109)unique_together
for foreign keys (#114)unique_together
meta Model option.all()
actually returns the _query property as was documented.related_name
for ForeignKey fields.Added basic DB driver Capabilities.
Test runner now has the ability to skip tests conditionally, based on the DB driver Capabilities:
@requireCapability(dialect='sqlite')
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.
.explain()
method on QuerySet
.required
read-only property to fieldsBigIntField
TimeDeltaField
BigIntField
can also be used as a primary key field..exclude()
method for QuerySetNOT
query (~Q(...)
).. rst-class:: emphasize-children
Tortoise.init()
and test runner to not re-create connections per test, so now tests pass when using an SQLite in-memory databaseinitializer(loop=loop)
nose2
pluginpy.test
aiosqlite>=0.7.0
pypika>=0.15.6
aiosqlite
as a required dependencyexecute_script()
now annotates errors just like execute_query()
, to reduce confusionaiosqlite>=0.6.0
for performance fixtortoise.run_async()
helper function to make smaller scripts easier to run. It cleans up connections automatically.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:
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(
db_url='sqlite://db.sqlite3',
modules={'models': ['app.models']}
)
# Generate the schema
await Tortoise.generate_schemas()
For more info, please have a look at :ref:`init_app`
transactions
module for implicit working with transactionsinitializer()
and finalizer()
to set up and tear down DB state... rst-class:: emphasize-children
__slots__
where it was easy to do. (Changes class instances from dicts into tuples, memory savings)JSONField
is now promoted to a standard field.DecimalField
and BooleanField
to work as expected on SQLite.FloatField
..get(...)
shortcut on query set.values()
and values_list()
now converts field values to python typesthrough
parameter honouring for ManyToManyField
Added support for nested queries for values
and values_list
:
result = await Event.filter(id=event.id).values('id', 'name', tournament='tournament__name')
result = await Event.filter(id=event.id).values_list('id', 'participants__name')
DatetimeField
and DateField
to work as expected on SQLite.PyLint
plugin.JSONField
.annotate()
method and basic aggregation funcsPrefetch
objectcontains
and other filter modifiers.default
now accepts functions.unique
flag for fieldsAdded schema generation and more options for fields:
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()
Tortoise.init(client)
await generate_schema(client)
Added filtering and ordering by related models fields:
await Tournament.filter(
events__name__in=['1', '3']
).order_by('-events__participants__name').distinct()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。