Quickstart

This guide walks through defining a schema, writing rows, and reading them back.

Tip

Follow along in an interactive Python session.

Model Definition

A Peewee application starts with a Database object and one or more Model classes. The database object manages connections; model classes map to tables.

import datetime
from peewee import *

# An in-memory SQLite database. Or use PostgresqlDatabase or MySQLDatabase.
db = SqliteDatabase(':memory:')

class BaseModel(Model):
    """All models inherit this to share the database connection."""
    class Meta:
        database = db

class User(BaseModel):
    username = TextField(unique=True)

class Tweet(BaseModel):
    user = ForeignKeyField(User, backref='tweets')
    content = TextField()
    timestamp = DateTimeField(
        default=datetime.datetime.now,
        index=True)
  • BaseModel exists only to carry the database setting. Every subclass inherits it automatically.

  • Peewee adds an auto-incrementing integer id primary key to any model that does not declare its own.

  • ForeignKeyField links Tweet to User. The backref='tweets' parameter means every User instance gains a tweets attribute.

Create the Tables

db.connect()
db.create_tables([User, Tweet])

create_tables() generates CREATE TABLE statements for each model. By default create_table() specifies safe=True, which uses CREATE TABLE IF NOT EXISTS, making it safe to call on every startup.

Writing Data

Create a row with create() (one step) or instantiate a model and call save() (two steps):

# One-step creation - returns the saved instance.
charlie = User.create(username='charlie')
huey = User.create(username='huey')

# Two-step creation.
t = Tweet(user=charlie, content='Hello, world!')
t.save()

Tweet.create(user=charlie, content='My second tweet.')
Tweet.create(user=huey, content='meow')

To update an existing row, modify attributes and call save() again:

charlie.username = 'charlie_admin'
charlie.save()

To delete a row:

stale_tweet = Tweet.get(Tweet.content == 'My second tweet.')
stale_tweet.delete_instance()

Reading Data

Retrieve a single row with get(). It raises DoesNotExist if no match is found:

user = User.get(User.username == 'charlie_admin')
print(user.id, user.username)

Retrieve multiple rows with select(). The result is a lazy query. Rows are fetched only when you iterate:

for tweet in Tweet.select():
    print(tweet.content)

Filter with where():

for tweet in Tweet.select().where(Tweet.user == charlie):
    print(tweet.content)

for tweet in Tweet.select().where(Tweet.timestamp.year == 2026):
    print(tweet.content)

Sort with order_by():

for tweet in Tweet.select().order_by(Tweet.timestamp.desc()):
    print(tweet.timestamp, tweet.content)

Join to combine data from related tables in a single query:

# Select each tweet with its author in one query.
query = (Tweet
         .select(Tweet, User)
         .join(User)
         .order_by(Tweet.timestamp.desc()))

for tweet in query:
    print(tweet.user.username, '->', tweet.content)

Simple Aggregates

How many tweets are in the database:

Tweet.select().count()

When the most-recent tweet was added:

Tweet.select(fn.MAX(Tweet.timestamp)).scalar()

Close the Connection

When done using the database, close the connection:

db.close()

In a web application you would open the connection when a request arrives and close it when the response is sent. See Framework Integration for framework-specific patterns.

Working with Existing databases

If you have an existing database, peewee can generate models using pwiz - Model Generator. For example to generate models for a Postgres database named blog:

python -m pwiz -e postgresql blog > blog_models.py

What Next

Each concept introduced above is covered in full detail in the following documents:

  • Database - connection options, multiple backends, run-time configuration, connection pooling.

  • Models and Fields - field types, field parameters, model Meta options, indexes, primary keys.

  • Relationships and Joins - how foreign keys work at runtime, joins, the N+1 problem, many-to-many relationships.

  • Querying - the full SELECT API: filtering, sorting, aggregates, window functions, CTEs.

  • Writing Data - INSERT, UPDATE, DELETE, bulk operations, upsert.

  • Transactions - atomic blocks, nesting, savepoints.

For a complete worked example building a small web application, see Example app.