NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #563 most downloaded on PyPI
a little orm
Last release 2 days ago
27 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
16 years old
222 releases · first in 2010
Allow aggregate functions to support an ORDER BY clause, via the addition of an order_by() method to the function (fn) instance. Refs #2094.
ORDER BY clause, via the addition
of an order_by() method to the function (fn) instance. Refs #2094.prefetch() bug, where related "backref" instances were marked as dirty,
even though they had no changes. Fixes #2091.LIMIT 0. Previously a limit of 0 would be translated into
effectively an unlimited query on MySQL. References #2084.JSONField.concat() accepts expressions as arguments.One column per quarter.
Fix a regression when specifying keyword arguments to the atomic() or transaction() helper methods. Note: this only occurs if you were using Sqlite an
Fix a regression when specifying keyword arguments to the atomic() or
transaction() helper methods. Note: this only occurs if you were using Sqlite
and were explicitly setting the lock_type= parameter.
This will be a notable release as it adds support for CockroachDB, a distributed, horizontally-scalable SQL database.
This will be a notable release as it adds support for CockroachDB, a distributed, horizontally-scalable SQL database.
FOR UPDATE clause to specify one or more tables (FOR UPDATE OF...).LATERAL join.exc.orig on the
wrapped exception.SMALLINT columns in Postgres schema reflection.atomic()
and transaction() context-manager/decorator.filter() API
across several tables (#2063).Bulk insert (insert_many() and insert_from()) will now return the row count instead of the last insert ID. If you are using Postgres, peewee will cont
insert_many() and insert_from()) will now return the row
count instead of the last insert ID. If you are using Postgres, peewee will
continue to return a cursor that provides an iterator over the newly-inserted
primary-key values by default. This behavior is being retained by default for
compatibility. Postgres users can simply specify an empty returning() call
to disable the cursor and retrieve the rowcount instead.alter_column_type() method.Database.is_connection_usabe() method, which attempts to look at the
status of the underlying DB-API connection to determine whether the
connection is usable.materialized parameter, which can be
used to control Postgres' optimization fencing around CTEs.BloomFilter.from_buffer() method for populating a bloom-filter from
the output of a previous call to the to_buffer() method.commit() and rollback() methods to no-op if the
database is in auto-commit mode.generate_always= option to the IdentityField (defaults to False).Implement hash interface for Alias instances, allowing them to be used in multi-source queries.
hash interface for Alias instances, allowing them to be used in
multi-source queries.Fix bug in new _pk / get_id() implementation for models that explicitly have disabled a primary-key.
_pk / get_id() implementation for models that explicitly
have disabled a primary-key.Fixes #1991. This particular issue involves joining 3 models together in a chain, where the outer two models are empty. Previously peewee would make t
Model._pk and get_id() interfaces so they
no longer introduce the possibility of accidentally resolving the FK.Field.contains(), startswith() and endswith() to compare against
another column-like object or expression.TimestampField resolution cleanup. Now values 0 and 1 will resolve to a
timestamp resolution of 1 second. Values 2-6 specify the number of decimal
places (hundredths to microsecond), or alternatively the resolution can still
be provided as a power of 10, e.g. 10, 1000 (millisecond), 1e6 (microsecond).dataset extension.dataset.Table class for doing primary-key lookup,
assignment, or deletion.ReconnectMixin helper to work with mysql-connector.PostgresqlExtDatabase and MySQLConnectorDatabase did not
respect the autoconnect setting.Add a helper to playhouse.mysql_ext for creating Match full-text search expressions.
playhouse.mysql_ext for creating Match full-text search
expressions.TimestampField for accessing the year, month,
day, etc., within a SQL expression.to_timestamp() helper for DateField and DateTimeField that
produces an expression returning a unix timestamp.autoconnect parameter to Database classes. This parameter defaults to
True and is compatible with previous versions of Peewee, in which executing
a query on a closed database would open a connection automatically. To make
it easier to catch inconsistent use of the database connection, this behavior
can now be disabled by specifying autoconnect=False, making an explicit
call to Database.connect() needed before executing a query.isolation_level to be specified when initializing a Postgres db.cursor.description tells us, which is buggy in older Sqlite).insert_many() and insert()
methods.ValueError stating that multiple FKs existed.date_trunc() behavior. Previously, truncating a datetime to
month resolution would return '2019-08' for example. As of 3.10.0, the
Sqlite and MySQL date_trunc implementation returns a full datetime, e.g.
'2019-08-01 00:00:00'.Json() helper.
In this version, Peewee now dumps the json to a string and applies an
explicit cast to the underlying JSON data-type (e.g. json or jsonb).model_to_dict.Support nesting the Database instance as a context-manager. The outermost block will handle opening and closing the connection along with wrapping eve
Database instance as a context-manager. The outermost
block will handle opening and closing the connection along with wrapping
everything in a transaction. Nested blocks will use savepoints.session_start(), session_commit() and session_rollback()
interfaces to the Database object to support using transactional controls in
situations where a context-manager or decorator is awkward.isolation_level=None in SQLite connection constructor rather than
afterwards using the setter.create_table() method to Select query to implement CREATE TABLE AS.Added small helper for setting timezone when using Postgres.
VALUES clause.TimestampField as a power-of-10.INSERT queries when the primary-key is not an
auto-incrementing integer, but is generated by the database server (eg uuid).Add Model.bulk_update() method for bulk-updating fields across multiple model instances. Docs.
Model.bulk_update() method for bulk-updating fields across multiple
model instances. Docs.lazy_load parameter to ForeignKeyField. When initialized with
lazy_load=False, the foreign-key will not use an additional query to
resolve the related model instance. Instead, if the related model instance is
not available, the underlying FK column value is returned (behaving like the
"_id" descriptor).Model.truncate_table() method.reflection and pwiz extensions now attempt to be smarter about
converting database table and column names into snake-case. To disable this,
you can set snake_case=False when calling the Introspector.introspect()
method or use the -L (legacy naming) option with the pwiz script.insert_many() no longer require specification of the
fields argument when the inserted rows are lists/tuples. In that case, the
fields will be inferred to be all model fields except any auto-increment id.DatabaseProxy, which implements several of the Database class context
managers. This allows you to reference some of the special features of the
database object without directly needing to initialize the proxy first.TSVectorField.match() method supports an
additional argument plain, which can be used to control the parsing of the
TS query.JSONField to the playhouse MySQL extension.Added cross-database support for NULLS FIRST/LAST when specifying the ordering for a query. Previously this was only supported for Postgres. Peewee wi
NULLS FIRST/LAST when specifying the
ordering for a query. Previously this was only supported for Postgres. Peewee
will now generate an equivalent CASE statement for Sqlite and MySQL.EXCLUDED namespace used with INSERT...ON CONFLICT
queries, when referencing values in the conflicting row data.Metadata class for setting the table name
at run-time. Setting the Model._meta.table_name directly may have appeared
to work in some situations, but could lead to subtle bugs. The new API is
Model._meta.set_table_name().DataSet that was originally reported on the
sqlite-web project.Nothing published for this version
Includes a bugfix for an AttributeError that occurs when using MySQL with the MySQLdb client. The 3.9.2 release includes fixes for a test failure.
Includes a bugfix for an AttributeError that occurs when using MySQL with the
MySQLdb client. The 3.9.2 release includes fixes for a test failure.
Added new document describing how to use peewee interactively.
__str__ implementation to all Query subclasses which converts the
query to a string and interpolates the parameters.sqlite_ext.JSONField regarding the serialization of data,
as well as the addition of options to override the JSON serialization and
de-serialization functions.index_type parameter to FieldDatabaseProxy, which allows one to use database-specific decorators
with an uninitialized Proxy object. See #1842 for discussion. Recommend
that you update any usage of Proxy for deferring database initialization to
use the new DatabaseProxy class instead.INSERT ... ON CONFLICT when the conflict target is a
partial index (e.g., contains a WHERE clause). The OnConflict and
on_conflict() APIs now take an additional conflict_where parameter to
represent the WHERE clause of the partial index in question. See #1860.playhouse.kv extension to use efficient upsert for all
database engines. Previously upsert was only supported for sqlite and mysql.orwhere() query filtering method, which will append the given
expressions using OR instead of AND. See #391 for old discussion.examples/ directoryselect_from() API for wrapping a query and selecting one or more
columns from the wrapped subquery. Docs.Bugfixes
prefetch() and fixed bug that could occur when mixing
self-referential foreign-keys and model aliases.TimestampField would treat zero values as None when
reading from the database.The default row-type for INSERT queries executed with a non-default RETURNING clause has changed from tuple to Model instances. This makes INSERT beha
Backwards-incompatible changes
INSERT queries executed with a non-default
RETURNING clause has changed from tuple to Model instances. This makes
INSERT behavior consistent with UPDATE and DELETE queries that specify
a RETURNING clause. To revert back to the old behavior, just append a call
to .tuples() to your INSERT ... RETURNING query.table_alias model Meta option. Previously, this
attribute could be used to specify a "vanity" alias for a model class in the
generated SQL. As a result of some changes to support more robust UPDATE and
DELETE queries, supporting this feature will require some re-working. As of
the 3.8.0 release, it was broken and resulted in incorrect SQL for UPDATE
queries, so now it is removed.New features
playhouse.shortcuts.ReconnectMixin, which can be used to implement
automatic reconnect under certain error conditions (notably the MySQL error
2006 - server has gone away).Bugfixes
ORDER BY
clause of a query.Sqlite SearchField now supports the match() operator, allowing full-text search to be performed on a single column (as opposed to the whole table).
New features
SearchField now supports the match() operator, allowing full-text
search to be performed on a single column (as opposed to the whole table).Changes
Bugfixes
ManyToManyField instances.Postgres BinaryJSONField now supports has_key(), concat() and remove() methods (though remove may require pg10+).
New features
BinaryJSONField now supports has_key(), concat() and
remove() methods (though remove may require pg10+).python_value() method to the SQL-function helper fn, to allow
specifying a custom function for mapping database values to Python values.Changes
QualifiedNames helper is no longer needed for certain types of queries.SqlCipherDatabase no longer accepts a kdf_iter parameter. To
configure the various SQLCipher encryption settings, specify the setting
values as pragmas when initializing the database.UUIDField and BinaryUUIDField to accept hexadecimal UUID strings as
well as raw binary UUID bytestrings (in addition to UUID instances, which
are already supported).ForeignKeyField to be created without an index.cast() to be chained (#1795).ManyToManyField supports foreign-keys to fields other than primary-keys.SQLITE_CONSTRAINT to
designate invalid queries against virtual tables.Bugfixes
order_by_extend(), thanks @nhatHero.DataSet CSV import/export did not support non-ASCII
characters in Python 3.x.model_to_dict would attempt to traverse explicitly disabled
foreign-key backrefs (#1785).Added table_settings model Meta option, which should be a list of strings specifying additional options for CREATE TABLE, which are placed *after* the
New features
table_settings model Meta option, which should be a list of strings
specifying additional options for CREATE TABLE, which are placed after
the closing parentheses.on_update and on_delete behavior for many-to-many
relationships when using ManyToManyField.Bugfixes
on_conflict() method:
conflict_constraint, which is currently only supported by Postgresql. Refs
issue #1737.IN
expressions. Previously the query would be assigned an alias, even though an
alias was not needed.frozenset to be correctly parameterized as a list of values.columns as a list of strings.CROSS JOIN for model select queries.Pool database close_all() method renamed to close_idle() to better reflect the actual behavior.
Backwards-incompatible changes
close_all() method renamed to close_idle() to better
reflect the actual behavior.InterfaceError when connect() or close() are
called on an uninitialized, deferred database object.New features
close_stale() method to the connection pool to support closing stale
connections.FlaskDB class in playhouse.flask_utils now accepts a model_class
parameter, which can be used to specify a custom base-class for models.Bugfixes
DeferredThroughModel, see #1708.ArrayField with an array of BlobField.Proxy databases to be used as a context-manager.sqlite3 driver, rather than from apsw.setup.py script. In this case I've added a
helper function which will reliably determine if the SQLite3 extensions can
be built. This follows the approach taken by the Python YAML package.Take a whole new approach, following what simplejson does. Allow the build_ext command class to fail, and retry without extensions in the event we run
Take a whole new approach, following what simplejson does. Allow the
build_ext command class to fail, and retry without extensions in the event we
run into issues building extensions. References #1676.
Add check in setup.py to determine if a C compiler is available before building C extensions. References #1676.
Add check in setup.py to determine if a C compiler is available before
building C extensions. References #1676.
Use ctypes.util.find_library to determine if libsqlite3 is installed. Should fix problems people are encountering installing when SQLite3 is not avail
Use ctypes.util.find_library to determine if libsqlite3 is installed.
Should fix problems people are encountering installing when SQLite3 is not
available.
Fixed issue with setup script. View commits
Fixed issue with setup script.
Support for Python 3.7, including bugfixes related to new StopIteration handling inside of generators.
ROWS or RANGE window frame types. For more
information, see the new frame type documentation.TimestampField now uses 64-bit integer data-type for storage.pwiz and playhouse.reflection to enable generating
models from VIEWs.setuptools for packaging.New guide to using window functions in Peewee.
legacy_table_names=False in your model's Meta options. For more details,
see table names
documentation.order_by and
partition_by arguments.FILTER (WHERE...) clauses with window functions and aggregates.IdentityField class suitable for use with Postgres 10's new identity
column type. It can be used anywhere AutoField or BigAutoField was being
used previously.prefetch() and ModelAlias to populate a
back-reference related model.New documentation for working with relationships in Peewee.
New features
database parameter to be specified with ModelSelect.get() method.
For discussion, see #1620.QualifiedNames helper to peewee module exports.temporary= meta option to support temporary tables.Database object to be passed to constructor of DataSet helper.Bug fixes
ValueError when joining and aliasing the join to a foreign-key's
object_id_name descriptor. Should prevent accidentally introducing O(n)
queries or silently ignoring data from a joined-instance.BigAutoField for it's primary-key.__repr__().SQL() was
no longer working. Refs #1645.Custom Model repr no longer use the convention of overriding __unicode__, and now use __str__.
Backwards-incompatible changes
repr no longer use the convention of overriding __unicode__,
and now use __str__.JSONField methods.
The documentation has been expanded to include more examples and the API has
been simplified to make it easier to work with. These changes do not have
any effect on the Postgresql JSON fields.New features
repr for model classes and fields.ForeignKeyField() accepts a new initialization parameter, deferrable, for
specifying when constraints should be enforced.BitField.flag() can be called without a value parameter for the common
use-case of using flags that are powers-of-2.SqliteDatabase pragmas can be specified as a dict (previously required a
list of 2-tuples).TableFunction (docs)
will print Python exception tracebacks raised in the initialize and
iterate callbacks, making debugging significantly easier.Bug fixes
migrator.add_column() where, if the field being added declared
a non-standard index type (e.g., binary json field with GIN index), this
index type was not being respected.database.table_exists() where the implementation did not match
the documentation. Implementation has been updated to match the
documentation.TableFunction implementation which raised errors if the
return value of the iterate() method was not a tuple.The regexp() operation is now case-sensitive for MySQL and Postgres. To perform case-insensitive regexp operations, use iregexp().
Backwards-incompatible changes
regexp() operation is now case-sensitive for MySQL and Postgres. To
perform case-insensitive regexp operations, use iregexp().BareField() field-type now supports all column constraints
except specifying the data-type. Previously it silently ignored any column
constraints.schema parameter for SQLite database introspection methods is no longer
ignored by default. The schema corresponds to the name given to an attached
database.ArrayField now accepts a new parameter field_kwargs, which is used to
pass information to the array field's field_class initializer.New features and other changes
JOIN helper.[table].[column].attach() and detach() methods to SQLite database, making it
possible to attach additional databases (e.g. an in-memory cache db).Added a BinaryUUIDField class for efficiently storing UUIDs in 16-bytes.
BinaryUUIDField class for efficiently storing UUIDs in 16-bytes.update_cache() logic so that when updating a single table
that was newly-added, we also ensure that all dependent tables are updated at
the same time. Refs coleifer/sqlite-web#42.More efficient implementation of model dependency-graph generation. Improves performance of recursively deleting related objects by omitting unnecessa
union(), union_all(), intersect() and except_() to the
Model-specific query implementations. This was an oversight that should
have been patched in 3.3.2, but is fixed in 3.3.3.unittest conventions.Add methods for union(), union_all, intersect() and except_(). Previously, these methods were only available as operator overloads.
union(), union_all, intersect() and except_().
Previously, these methods were only available as operator overloads.Fixed long-standing bug in 3.x regarding using column aliases with queries that utilize the ModelCursorWrapper (typically queries with one or more joi
Added support for SQLite's new ON CONFLICT clause, which is modelled on the syntax used by Postgresql and will be available in SQLite 3.24.0 and onwar
ON CONFLICT clause, which is modelled on the
syntax used by Postgresql and will be available in SQLite 3.24.0 and onward.Added ValuesList for representing values lists. Docs.
ValuesList for representing values lists. Docs.DateTimeField, DateField and TimeField will parse formatted-strings
before sending to the database. Previously this only occurred when reading
values from the database.Smarter handling of model-graph when dealing with compound queries (union, intersect, etc). #1579.
ModelSelect.switch() is called without any arguments, default to the
query's model. Refs #1573.pwiz tool will capture column defaults defined as part of the table schema.
pwiz tool will capture column defaults defined as part of the table schema.reuse_if_open parameter has effect on pooled databases.Added support for passing Model classes to the returning() method when you intend to return all columns for the given model.
Model classes to the returning() method when
you intend to return all columns for the given model.drop_sequences parameter to drop_table() method which allows you to
conditionally drop any user-defined sequences when dropping the table.Notice: the default mysql driver for Peewee has changed to pymysql in version 3.2.1. In previous versions, if both *mysql-python* and *pymysql* were i
Notice: the default mysql driver for Peewee has changed to pymysql in version 3.2.1. In previous versions, if both mysql-python and pymysql were installed, Peewee would use mysql-python. As of 3.2.1, if both libraries are installed Peewee will use pymysql.
playhouse.mysql_ext which includes
MySQLConnectorDatabase, a database implementation that works with the
mysql-connector driver.ColumnMetadata class which captures a database column's
default value. ColumnMetadata is returned by Database.get_columns().The 3.2.0 release introduces a potentially backwards-incompatible change. The only users affected will be those that have implemented custom Field typ
The 3.2.0 release introduces a potentially backwards-incompatible change. The
only users affected will be those that have implemented custom Field types
with a user-defined coerce method. tl/dr: rename the coerce attribute to
adapt and you should be set.
The Field.coerce method has been renamed to Field.adapt. The purpose of
this method is to convert a value from the application/database into the
appropriate Python data-type. For instance, IntegerField.adapt is simply the
int built-in function.
The motivation for this change is to support adding metadata to any AST node instructing Peewee to not coerce the associated value. As an example, consider this code:
class Note(Model):
id = AutoField() # autoincrementing integer primary key.
content = TextField()
# Query notes table and cast the "id" to a string and store as "id_text" attr.
query = Note.select(Note.id.cast('TEXT').alias('id_text'), Note.content)
a_note = query.get()
print((a_note.id_text, a_note.content))
# Prior to 3.2.0 the CAST is "un-done" because the value gets converted
# back to an integer, since the value is associated with the Note.id field:
(1, u'some note') # 3.1.7, e.g. -- "id_text" is an integer!
# As of 3.2.0, CAST will automatically prevent the conversion of field values,
# which is an extension of a more general metadata API that can instruct Peewee
# not to convert certain values.
(u'1', u'some note') # 3.2.0 -- "id_text" is a string as expected.
If you have implemented custom Field classes and are using coerce to
enforce a particular data-type, you can simply rename the attribute to adapt.
Old versions of SQLite do not strip quotation marks from aliased column names in compound queries (e.g. UNION). Fixed in 3.2.0.
For all the winblows lusers out there, added an option to skip compilation of the SQLite C extensions during installation. Set env var NO_SQLITE=1 and
For all the winblows lusers out there, added an option to skip compilation of
the SQLite C extensions during installation. Set env var NO_SQLITE=1 and run
setup.py install and you should be able to build without requiring SQLite.
Added rekey() method to SqlCipher database for changing encryption key and documentation for set_passphrase() method.
rekey() method to SqlCipher database for changing encryption key and
documentation for set_passphrase() method.convert_values parameter to ArrayField constructor, which will
cause the array values to be processed using the underlying data-type's
conversion logic.TimestampField with sub-second resolutions.drop_table().signals extension.Fixed Python 2/3 incompatibility with itertools.izip_longest().
Fixed Python 2/3 incompatibility with itertools.izip_longest().
Added BigAutoField to support 64-bit auto-incrementing primary keys.
BigAutoField to support 64-bit auto-incrementing primary keys.DataSet. Previously the JSON export used ISO-8601 by default. See #1536.Database.batch_commit helper to wrap iterators in chunked
transactions. See #1539 for discussion.Fixed issue where scope-specific settings were being updated in-place instead of copied. #1534.
ForeignKeyField did not add it to the model's
"dirty" fields list. #1530.prefetch() with ManyToManyField. Thanks
to @iBelieve for the patch. #1531.JSON data-type for SQLite JSONField instances.json_contains function for use with SQLite json1 extension.Investigating #1522, it occurred to me that INSERT queries with non-default *RETURNING* clauses (postgres-only feature) should always return a cursor
Investigating #1522, it occurred to me that INSERT queries with non-default RETURNING clauses (postgres-only feature) should always return a cursor object. Previously, if executing a single-row INSERT query, the last-inserted row ID would be returned, regardless of what was specified by the RETURNING clause.
This change only affects INSERT queries with non-default RETURNING clauses and will cause a cursor to be returned, as opposed to the last-inserted row ID.
Fixed bug when using Model.alias() when the model defined a particular database schema.
Model.alias() when the model defined a particular
database schema.SchemaManager.create_foreign_key API to simplify adding constraints
when dealing with circular foreign-key relationships. Updated docs
accordingly.Migrator.add_foreign_key_constraint so that it
can be used with Postgresql (in addition to MySQL).PickleField to the playhouse.fields module. Docs.CompressedField when using Python 3.KeyValue API in playhouse.kv module. Docs.Database.bind() has been renamed to Database.bind_ctx(), to more closely match the semantics of the corresponding model methods, Model.bind() and Mode
Database.bind() has been renamed to Database.bind_ctx(), to more closely
match the semantics of the corresponding model methods, Model.bind() and
Model.bind_ctx(). The new Database.bind() method is a one-time operation
that binds the given models to the database. See documentation:
Support for more types of mappings in insert_many(), refs #1495.
insert_many(), refs #1495.tuples() on a ModelRaw query. This was reported
originally as a bug with sqlite-web CSV export. See coleifer/sqlite-web#38.Improved error messages when attempting to use a database class for which the corresponding driver is not installed.
Fix schema inheritance regression, #1485.
schema inheritance regression, #1485.Improve model graph resolution when iterating results of a query. Refs #1482.
Use same schema used for reflection in generated models.
schema used for reflection in generated models.pragmas set on deferred Sqlite database if database is
re-initialized without re-specifying pragmas.Fix bug creating model instances on Postgres when model does not have a primary key column.
Fix bug where simple field aliases were being ignored. Fixes #1473.
Fix queries of the form INSERT ... VALUES (SELECT...) so that sub-select is wrapped in parentheses.
Add note to changelog about cursor() method.
cursor() method.Fix Database.drop_tables() signature to support cascade argument - #1453.
Database.drop_tables() signature to support cascade argument - #1453.ModelBase for convenient counting.coerce keyword argument with fn.XXX() - #1463.Add deprecation notice if passing autocommit as keyword argument to the Database initializer. Refs #1452.
autocommit as keyword argument to the
Database initializer. Refs #1452.JSONPath and "J" helpers to sqlite extension.Add support for passing cascade=True when dropping tables. Fixes #1449.
cascade=True when dropping tables. Fixes #1449.Your coding agent can read these notes before it upgrades. Set up the MCP server →