Skillversitas

Installation and Setup

Peewee installs as a single pip package with no required dependencies for SQLite, and the first working setup is a model, a connection, a table creation, and a row - the four-line smoke test that proves the ORM, the driver, and the database all work together. The practical concerns are the database backend (SQLite for development, PostgreSQL or MySQL for production), the connection lifecycle, and the project layout that keeps the models and the database config in one place. This chapter covers the install, the backend choices, the smoke test, and the module shape a real Peewee project uses.

Install

# the core - SQLite support is built in
pip install peewee

# verify
python -c "import peewee; print(peewee.__version__)"

# production backends are the standard drivers:
# PostgreSQL needs psycopg2 (or psycopg)
pip install psycopg2-binary
# MySQL needs mysqlclient (or PyMySQL)
pip install mysqlclient

The peewee package includes the SQLite driver (via the standard library's sqlite3), so the base install is enough for development. The production backends use the usual Python drivers - psycopg2 for PostgreSQL, mysqlclient for MySQL - and Peewee's PostgresqlDatabase/MySQLDatabase classes take the same connection parameters those drivers do. The version check is worth pinning in requirements, because a few query-expression details shifted across minor versions, and pinning avoids a surprise when the stack upgrades.

The Smoke Test

from peewee import *

# 1. the connection - in-memory SQLite for the test
db = SqliteDatabase(":memory:")

# 2. a model
class Note(Model):
    text = TextField()
    class Meta:
        database = db

# 3. create the table
db.connect()
Note.create_table()

# 4. a row, read back
n = Note.create(text="hello peewee")
print(Note.get(Note.id == n.id).text)   # hello peewee
print(Note.select().count())            # 1

db.close()

Four steps, and each one is the pattern the rest of the tutorial builds on. The SqliteDatabase(":memory:") is a connection to a fresh, empty database that lives only for the process - the standard development and test target. The model declares its fields and, in the Meta class, names the database it belongs to. create_table() issues the CREATE TABLE (the migrations chapter covers changes after creation). Note.create(...) inserts a row and returns the instance, and Note.get(...) reads one back. If this prints without error, the ORM, the driver, and the database are all working - the same smoke-test discipline from the other tutorials, applied to the data layer.

The Backends and Their Parameters

from peewee import SqliteDatabase, PostgresqlDatabase, MySQLDatabase

# SQLite: a file, or :memory:
dev_db = SqliteDatabase("app.db")

# PostgreSQL: the standard connection parameters
prod_db = PostgresqlDatabase(
    "appdb",
    user="app",
    password="secret",
    host="db.internal",
    port=5432,
)

# MySQL: the same shape
mysql_db = MySQLDatabase(
    "appdb",
    user="app",
    password="secret",
    host="db.internal",
    port=3306,
)

The three database classes take the parameters their drivers expect, and the model's Meta.database points at whichever one the app is running against. The pattern that keeps this clean is a single database.py module that constructs the right connection from the environment (a DATABASE_URL or a set of env vars) and exposes one db object - the models import that one object, and switching from SQLite to PostgreSQL is a config change, not a code change. The :memory: form is the test target; a file path is the development target; the host/user/password form is production. Same models, same queries, different connection object.

Project Shape

myapp/
  database.py      # the connection, built from the environment
  models.py        # the Model subclasses
  migrations/      # the playhouse migrate scripts (the migrations chapter)
  main.py          # the app, imports database.db and models

The convention: database.py owns the connection (built from the environment, one exported db), models.py owns the models (which import db and set Meta.database), and the rest of the app imports both. The migrations/ directory holds the migration scripts the migrations chapter generates. This three-file core is the shape every Peewee project should have, because it makes the data layer a single, inspectable unit - the connection, the schema, and the migrations all live where you expect them, and a new developer can read the data model in one file.

The Connection Lifecycle

  • db.connect() opens the connection; db.close() closes it. SQLite is permissive about this, but the production backends are not - a connection that is never closed is a leaked resource.
  • Autoconnect - Peewee will connect lazily on the first query if you have not called connect(), which is convenient for scripts and a footgun for long-running apps; the explicit connect/close (or the pooling chapter's pool) is the production shape.
  • One connection per thread - a raw database connection is not safe to share across threads; the threading case is the pooling chapter's territory.
  • Close in a finally (or a context manager) in scripts, so an error between connect and close does not leak the connection.

The lifecycle rule is the same as the file-handling rule from the storage tutorials: open explicitly, close on every path, and for a long-running app let the pool (the playhouse-pooling chapter) manage the connections instead of the app. With a connection and a first model running, the next chapter defines the real models - the fields and the mappings that make the ORM useful.

Summary

Install with pip install peewee (SQLite is built in; add psycopg2-binary or mysqlclient for the production backends), and run the four-line smoke test - a SqliteDatabase(":memory:"), a model, create_table(), a create and a get - to prove the ORM, driver, and database together. Choose the backend class (SqliteDatabase, PostgresqlDatabase, MySQLDatabase) with the standard connection parameters, and keep the connection in a single database.py that the models import, so switching databases is a config change. Follow the connection lifecycle - explicit connect, close on every path, one connection per thread, the pool for long-running apps - and the project shape (database.py, models.py, migrations/) gives the data layer a single inspectable home. The next chapter defines the models, which is where the ORM starts earning its keep.