Peewee ORM
raw JSON → 4.0.3 verified Tue May 12 auth: no python install: verified
Peewee is a simple and small Python ORM (Object-Relational Mapper) that provides an expressive interface for database operations. It supports SQLite, MySQL/MariaDB, and PostgreSQL, and offers flexible query-building, asyncio support, and numerous extensions. The library is actively maintained with frequent releases, currently at version 4.0.3.
pip install peewee Common errors
error ModuleNotFoundError: No module named 'peewee' ↓
cause The 'peewee' library is not installed in the Python environment being used, or there's an issue with the Python path preventing the interpreter from finding the installed package.
fix
Ensure Peewee is installed by running
pip install peewee or pip3 install peewee in your terminal for the correct Python environment. error peewee.OperationalError: database is locked ↓
cause This error commonly occurs with SQLite when multiple threads or processes attempt to write to the database concurrently, or when a database connection is not properly closed.
fix
Implement proper connection management, such as using
with db.atomic(): for transactions, or increasing the timeout parameter when initializing SqliteDatabase (e.g., SqliteDatabase('my_app.db', timeout=10)). For multi-threaded applications, ensure each thread has its own connection or use a connection pool. error peewee.DoesNotExist: Instance matching query does not exist ↓
cause This exception is raised by `Model.get()` when no record in the database matches the specified query criteria.
fix
Use
Model.get_or_none() to return None instead of raising an exception if no record is found, or wrap the Model.get() call in a try-except peewee.DoesNotExist block to gracefully handle cases where a record might not exist. error peewee.OperationalError: no such column: [column_name] ↓
cause The database schema does not match the model definition in your Python code. This often happens after adding new fields to a model without updating the corresponding database table, or if the table was created manually without all expected columns (including Peewee's implicit 'id' primary key).
fix
Update your database schema to match the model definition. This can often be done by running
db.create_tables([YourModel], safe=True) (which creates tables if they don't exist, but doesn't modify existing ones) or by using Peewee's migration system to add/alter columns. error AttributeError: 'module' object has no attribute 'Model' ↓
cause This specific `AttributeError` typically arises when a user's Python file is inadvertently named `peewee.py`, which then 'shadows' the actual installed `peewee` library. Python imports the local file instead of the library, and the local file does not define `Model`.
fix
Rename your Python script (e.g., from
peewee.py to my_models.py or database_setup.py) to avoid conflicting with the peewee library's module name. Warnings
breaking Peewee 4.0.2 removed all Python 2.x compatibility code. Projects still on Python 2 must use an older Peewee version (<=3.x). ↓
fix Upgrade to Python 3.x or pin Peewee to a 3.x version.
breaking In `playhouse.dataset` (Peewee 4.0.2), the default binary data serialization changed from base64 to hex. If you rely on base64 encoding for existing data, you must explicitly specify `base64_bytes=True` during deserialization. ↓
fix For existing base64 encoded data, use `base64_bytes=True` when deserializing. For new data, be aware of the hex default.
breaking `SqliteExtDatabase` was removed in Peewee 4.0.1 as it served no significant purpose in Peewee 4.0. Use `SqliteDatabase` instead. ↓
fix Replace `SqliteExtDatabase` imports and instantiations with `SqliteDatabase`.
breaking As of Peewee 3.19.0, SQLite C extensions are no longer built and shipped by default. If you require these extensions (e.g., for FTS5 ranking functions or fuzzy string matching), you need to install Peewee from the sdist. ↓
fix Install using `pip install peewee --no-binary :all:` or `pip install pysqlite3 peewee --no-binary :all:` if using `pysqlite3`.
breaking In Peewee 3.18.0, the behavior of `postgresql_ext.BinaryJSONField.contains()` changed. It now *always* uses the JSONB contains operator (`@>`). Previously, passing a string would perform a JSON key existence check (`?`). ↓
fix To check for key existence (the old string behavior), use `BinaryJSONField.has_key()` instead.
gotcha Peewee uses bitwise operators (`&` for AND, `|` for OR) for logical operations in queries, not Python's `and`/`or` keywords, because Python coerces logical operations to boolean values. Similarly, for 'IN' queries, use the `.in_()` method instead of the Python `in` operator. ↓
fix Use `(Field == value) & (OtherField > other_value)` for AND, `(Field == value) | (OtherField > other_value)` for OR, and `Field.in_([list, of, values])` for IN operations.
breaking Peewee 3.16.0 changed how it initializes connections to DB-API drivers. It now places the driver in autocommit mode directly, instead of emulating autocommit. If you directly use `Database.connection()` or `Database.cursor()`, your queries will now execute in autocommit mode. ↓
fix Be aware that direct driver interactions will be autocommitted. Peewee's `atomic()` blocks still manage transactions as before.
Install
pip install peewee[mysql] pip install peewee[postgres] pip install peewee[psycopg3] pip install peewee --no-binary :all: Install compatibility verified last tested: 2026-05-12
python os / libc variant status wheel install import disk
3.10 alpine (musl) peewee wheel - 0.08s 19.0M
3.10 alpine (musl) peewee - - 0.09s 19.0M
3.10 alpine (musl) peewee build_error - - - -
3.10 alpine (musl) peewee - - - -
3.10 alpine (musl) mysql wheel - 0.11s 19.4M
3.10 alpine (musl) mysql - - 0.12s 19.4M
3.10 alpine (musl) postgres wheel - 0.12s 27.6M
3.10 alpine (musl) postgres - - 0.13s 27.6M
3.10 alpine (musl) psycopg3 wheel - 0.38s 36.5M
3.10 alpine (musl) psycopg3 - - 0.43s 36.5M
3.10 slim (glibc) peewee wheel 1.6s 0.06s 19M
3.10 slim (glibc) peewee - - 0.07s 19M
3.10 slim (glibc) peewee build_error - 10.7s - -
3.10 slim (glibc) peewee - - - -
3.10 slim (glibc) mysql wheel 1.7s 0.08s 20M
3.10 slim (glibc) mysql - - 0.09s 20M
3.10 slim (glibc) postgres wheel 1.8s 0.08s 31M
3.10 slim (glibc) postgres - - 0.10s 31M
3.10 slim (glibc) psycopg3 wheel 2.3s 0.28s 40M
3.10 slim (glibc) psycopg3 - - 0.31s 40M
3.11 alpine (musl) peewee wheel - 0.17s 21.2M
3.11 alpine (musl) peewee - - 0.21s 21.2M
3.11 alpine (musl) peewee build_error - - - -
3.11 alpine (musl) peewee - - - -
3.11 alpine (musl) mysql wheel - 0.22s 21.7M
3.11 alpine (musl) mysql - - 0.27s 21.7M
3.11 alpine (musl) postgres wheel - 0.22s 29.9M
3.11 alpine (musl) postgres - - 0.26s 29.9M
3.11 alpine (musl) psycopg3 wheel - 0.63s 39.3M
3.11 alpine (musl) psycopg3 - - 0.77s 39.3M
3.11 slim (glibc) peewee wheel 1.7s 0.15s 22M
3.11 slim (glibc) peewee - - 0.15s 22M
3.11 slim (glibc) peewee build_error - 10.2s - -
3.11 slim (glibc) peewee - - - -
3.11 slim (glibc) mysql wheel 1.8s 0.19s 22M
3.11 slim (glibc) mysql - - 0.20s 22M
3.11 slim (glibc) postgres wheel 1.8s 0.19s 33M
3.11 slim (glibc) postgres - - 0.20s 33M
3.11 slim (glibc) psycopg3 wheel 2.2s 0.59s 43M
3.11 slim (glibc) psycopg3 - - 0.61s 43M
3.12 alpine (musl) peewee wheel - 0.13s 13.0M
3.12 alpine (musl) peewee - - 0.14s 13.0M
3.12 alpine (musl) peewee build_error - - - -
3.12 alpine (musl) peewee - - - -
3.12 alpine (musl) mysql wheel - 0.15s 13.5M
3.12 alpine (musl) mysql - - 0.18s 13.5M
3.12 alpine (musl) postgres wheel - 0.16s 21.6M
3.12 alpine (musl) postgres - - 0.18s 21.6M
3.12 alpine (musl) psycopg3 wheel - 0.74s 30.9M
3.12 alpine (musl) psycopg3 - - 0.84s 30.9M
3.12 slim (glibc) peewee wheel 1.5s 0.13s 14M
3.12 slim (glibc) peewee - - 0.14s 14M
3.12 slim (glibc) peewee build_error - 14.0s - -
3.12 slim (glibc) peewee - - - -
3.12 slim (glibc) mysql wheel 1.6s 0.17s 14M
3.12 slim (glibc) mysql - - 0.18s 14M
3.12 slim (glibc) postgres wheel 1.7s 0.17s 25M
3.12 slim (glibc) postgres - - 0.17s 25M
3.12 slim (glibc) psycopg3 wheel 2.0s 0.73s 34M
3.12 slim (glibc) psycopg3 - - 0.82s 34M
3.13 alpine (musl) peewee wheel - 0.13s 12.8M
3.13 alpine (musl) peewee - - 0.13s 12.7M
3.13 alpine (musl) peewee build_error - - - -
3.13 alpine (musl) peewee - - - -
3.13 alpine (musl) mysql wheel - 0.16s 13.2M
3.13 alpine (musl) mysql - - 0.17s 13.1M
3.13 alpine (musl) postgres wheel - 0.16s 21.4M
3.13 alpine (musl) postgres - - 0.20s 21.3M
3.13 alpine (musl) psycopg3 wheel - 0.76s 30.3M
3.13 alpine (musl) psycopg3 - - 0.82s 30.2M
3.13 slim (glibc) peewee wheel 1.6s 0.13s 13M
3.13 slim (glibc) peewee - - 0.13s 13M
3.13 slim (glibc) peewee build_error - 12.7s - -
3.13 slim (glibc) peewee - - - -
3.13 slim (glibc) mysql wheel 1.6s 0.16s 14M
3.13 slim (glibc) mysql - - 0.17s 14M
3.13 slim (glibc) postgres wheel 1.8s 0.17s 25M
3.13 slim (glibc) postgres - - 0.17s 24M
3.13 slim (glibc) psycopg3 wheel 2.0s 0.74s 34M
3.13 slim (glibc) psycopg3 - - 0.80s 33M
3.9 alpine (musl) peewee wheel - 0.07s 18.5M
3.9 alpine (musl) peewee - - 0.09s 18.5M
3.9 alpine (musl) peewee build_error - - - -
3.9 alpine (musl) peewee - - - -
3.9 alpine (musl) mysql wheel - 0.10s 18.9M
3.9 alpine (musl) mysql - - 0.12s 18.9M
3.9 alpine (musl) postgres wheel - 0.10s 27.1M
3.9 alpine (musl) postgres - - 0.12s 27.1M
3.9 alpine (musl) psycopg3 wheel - 0.35s 29.6M
3.9 alpine (musl) psycopg3 - - 0.38s 29.6M
3.9 slim (glibc) peewee wheel 1.9s 0.07s 19M
3.9 slim (glibc) peewee - - 0.08s 19M
3.9 slim (glibc) peewee build_error - 12.1s - -
3.9 slim (glibc) peewee - - - -
3.9 slim (glibc) mysql wheel 2.0s 0.09s 19M
3.9 slim (glibc) mysql - - 0.10s 19M
3.9 slim (glibc) postgres wheel 2.2s 0.10s 30M
3.9 slim (glibc) postgres - - 0.11s 30M
3.9 slim (glibc) psycopg3 wheel 2.7s 0.30s 33M
3.9 slim (glibc) psycopg3 - - 0.49s 33M
Imports
- Model
from peewee import Model - SqliteDatabase
from peewee import SqliteDatabase - PostgresqlDatabase
from peewee import PostgresqlDatabase - MySQLDatabase
from peewee import MySQLDatabase - CharField
from peewee import CharField - TextField
from peewee import TextField - ForeignKeyField
from peewee import ForeignKeyField - DateTimeField
from peewee import DateTimeField
Quickstart last tested: 2026-04-24
import datetime
from peewee import *
db = SqliteDatabase(':memory:') # Use an in-memory SQLite database
class BaseModel(Model):
class Meta:
database = db
class User(BaseModel):
username = CharField(unique=True)
class Tweet(BaseModel):
user = ForeignKeyField(User, backref='tweets')
content = TextField()
timestamp = DateTimeField(default=datetime.datetime.now)
def run_quickstart():
db.connect()
db.create_tables([User, Tweet])
# Create users
charlie = User.create(username='charlie')
huey = User.create(username='huey')
# Create tweets
Tweet.create(user=charlie, content='Hello from Charlie!')
Tweet.create(user=huey, content='Meow!')
Tweet.create(user=charlie, content='Another tweet.')
# Query data
print("\n--- All Tweets ---")
for tweet in Tweet.select().order_by(Tweet.timestamp.desc()):
print(f"{tweet.user.username} -> {tweet.content}")
# Get a single user's tweets
print("\n--- Charlie's Tweets ---")
for tweet in charlie.tweets:
print(f"{tweet.user.username} -> {tweet.content}")
db.close()
if __name__ == '__main__':
run_quickstart()