Install & Compatibility
Where this runs
tested against v4.4.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
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
This quickstart demonstrates how to define Peewee models, connect to an in-memory SQLite database, create tables, insert records, and query data with relationships. It showcases basic CRUD operations and how to iterate over query results.
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()
pwiz --version
Debug
Known issues
breakingPeewee 4.0.2 removed all Python 2.x compatibility code. Projects still on Python 2 must use an older Peewee version (<=3.x).fixUpgrade to Python 3.x or pin Peewee to a 3.x version.
affects: 4.0.2 and greater
breakingIn `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.fixFor existing base64 encoded data, use `base64_bytes=True` when deserializing. For new data, be aware of the hex default.
affects: 4.0.2 and greater
breaking`SqliteExtDatabase` was removed in Peewee 4.0.1 as it served no significant purpose in Peewee 4.0. Use `SqliteDatabase` instead.fixReplace `SqliteExtDatabase` imports and instantiations with `SqliteDatabase`.
affects: 4.0.1 and greater
breakingAs 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.fixInstall using `pip install peewee --no-binary :all:` or `pip install pysqlite3 peewee --no-binary :all:` if using `pysqlite3`.
affects: 3.19.0 and greater
breakingIn 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 (`?`).fixTo check for key existence (the old string behavior), use `BinaryJSONField.has_key()` instead.
affects: 3.18.0 and greater
gotchaPeewee 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.fixUse `(Field == value) & (OtherField > other_value)` for AND, `(Field == value) | (OtherField > other_value)` for OR, and `Field.in_([list, of, values])` for IN operations.
affects: All versions
breakingPeewee 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.fixBe aware that direct driver interactions will be autocommitted. Peewee's `atomic()` blocks still manage transactions as before.
affects: 3.16.0 and greater
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'peewee'
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.
fixEnsure Peewee is installed by running `pip install peewee` or `pip3 install peewee` in your terminal for the correct Python environment.
peewee.OperationalError: database is locked
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.
fixImplement 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. peewee.DoesNotExist: Instance matching query does not exist
This exception is raised by `Model.get()` when no record in the database matches the specified query criteria.
fixUse `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.
peewee.OperationalError: no such column: [column_name]
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).
fixUpdate 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.
AttributeError: 'module' object has no attribute 'Model'
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`.
fixRename 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.
Upgrade
Version history
4.4.0latest on PyPI · released Aug 23, 2026
Audit
Dependencies
pymysqloptionalRequired for MySQL/MariaDB database backend.
psycopg2-binaryoptionalRequired for PostgreSQL database backend (psycopg2).
psycopg[binary]optionalRequired for PostgreSQL database backend (psycopg3).
aiosqliteoptionalRequired for asyncio support with SQLite.
aiomysqloptionalRequired for asyncio support with MySQL/MariaDB.
asyncpgoptionalRequired for asyncio support with PostgreSQL.