a small, expressive orm -- supports postgresql, mysql, sqlite and cockroachdb
psycopg3
.jsonb
.list(query)
resulted in extra queries, #2871BigBitField
, #2802.add_column_default
and drop_column_default
migrator methods for specifying a server-side default value, #2803.star
attribute was causing issues for users who had a field named star on their models. This attribute is now renamed to __star__
. #2796.model_to_dict()
when only aliases are present.reconnect=
argument to ping()
if using MySQL 8.x.@db.transaction
decorator/ctx manager if an unhandled exception occurs. Previously, an unhandled exception that occurred in a nested transaction
context would trigger a rollback. The use of nested transaction
has long been discouraged in the documentation: the recommendation is to always use db.atomic
, which will use savepoints to properly handle nested blocks. However, the new behavior should make it easier to reason about transaction boundaries - see #2767 for discussion.BEGIN
in the reconnect-mixin. Given that no transaction has been started, reconnecting when beginning a new transaction ensures that a reconnect will occur if it is safe to do so.isolation_level
in db.atomic()
and db.transaction()
when using Postgres and MySQL/MariaDB, which will apply to the wrapped transaction. Note: Sqlite has supported a similar lock_type
parameter for some time.SQLITE_DETERMINISTIC
function flag. This allows user-defined Sqlite functions to be used in indexes and may be used by the query planner.ManyToManyField
to prevent setting/getting values on unsaved instances. This is worthwhile, since reading or writing a many-to-many has no meaning when the instance is unsaved.star()
helper to Source
base-class for selecting all columns.binary
types for mysql-connector and mariadb-connector.extract()
method to MySQL JSONField
for extracting a jsonpath.Fixes a longstanding issue with thread-safety of various decorators, including atomic()
, transaction()
, savepoint()
. The context-managers are unaffected. See #2709 for details.
legacy=True
flag.This release contains backwards-incompatible changes in the way Peewee initializes connections to the underlying database driver. Previously, peewee implemented autocommit semantics on-top of the existing DB-API transactional workflow. Going forward, Peewee instead places the DB-API driver into autocommit mode directly.
Why this change?
Previously, Peewee emulated autocommit behavior for top-level queries issued outside of a transaction. This necessitated a number of checks which had to be performed each time a query was executed, so as to ensure that we didn't end up with uncommitted writes or, conversely, idle read transactions. By running the underlying driver in autocommit mode, we can eliminate all these checks, since we are already managing transactions ourselves.
Behaviorally, there should be no change -- Peewee will still treat top-level
queries outside of transactions as being autocommitted, while queries inside of
atomic()
/ with db:
blocks are implicitly committed at the end of the
block, or rolled-back if an exception occurs.
How might this affect me?
Database.connection()
or Database.cursor()
, your queries will now be executed in autocommit mode.commit=
argument is deprecated for the cursor()
, execute()
and execute_sql()
methods.Database
implementation (whether for a database that is not officially supported, or for the purpose of overriding default behaviors), you will want to ensure that your connections are opened in autocommit mode.Other changes:
get_columns()
implementation now returns columns in their declared order.ReconnectMixin
if connection is lost while inside a transaction (if the transaction was interrupted presumably some changes were lost and explicit intervention is needed).db.Model
property to reduce boilerplate.prefetch()
queries with joins instead of subqueries (this helps overcome a MySQL limitation about applying LIMITs to a subquery).AVG
to whitelist to avoid coercing by default.pyproject.toml
to silence warnings from newer pips when wheel
package is not available.This release has a small helper for reducing boilerplate in some cases by exposing a base model class as an attribute of the database instance.
# old:
db = SqliteDatabase('...')
class BaseModel(Model):
class Meta:
database = db
class MyModel(BaseModel):
pass
# new:
db = SqliteDatabase('...')
class MyModel(db.Model):
pass
scalars()
query method (complements scalar()
), roughly equivalent to writing [t[0] for t in query.tuples()]
.