Quickstart

This guide walks through defining a schema, writing rows, and reading them back. It takes about ten minutes. Every concept introduced here is covered in depth in the following documents.

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)

Three things to notice:

  • 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:

# Fetch each tweet alongside its author's username.
# Without the join, accessing tweet.user.username would issue
# an extra query per tweet - see the N+1 section in Relationships.
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_db:

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.