Skip to content

Introduction to the ORM

The ORM implements Active Record: a class describes a table and an instance represents a row. It combines attributes, casts, queries, relationships and events. Database manages connections, drivers, SQL and transactions; the ORM builds plans on that same infrastructure.

flowchart TD
    C["Controller / service / command"] --> M["Model: attributes and lifecycle"]
    M --> Q["ModelQueryBuilder: query plan"]
    Q --> R["ConnectionResolver"]
    R --> D["Database connection manager"]
    D --> S["SQL compiler and driver"]
    S --> B[(Database)]
    B --> H["Rows → casts → model hydration"]
    H --> C

When a class is declared, ModelMeta collects columns, resolves the table and primary key, and prepares casts, accessors, scopes and listeners. Declaring a model never creates or alters tables: use migrations.

  1. Article({...}) builds a new in-memory instance and applies mass assignment rules.
  2. await article.save() generates an INSERT, maintains declared timestamps, adopts the generated identity and synchronizes original state.
  3. await Article.find(id) retrieves a row, applies casts and creates a persisted instance. It returns None when absent.
  4. Attribute changes are tracked against the original snapshot. Another save() writes those differences through UPDATE.
  5. delete() removes the row or stamps its soft delete column.

Declarations and builders are synchronous; terminals accessing data are asynchronous. Use these examples from a controller, service, command or task after application boot. The Database provider installs ConnectionResolver; querying before that setup raises OrmConfigurationException.

NeedAPI
Row with attribute policy, state and eventsA Model instance
Entity and relationship queriesArticle.query() or a delegated entry such as Article.where(...)
Table rows, aggregates and writes without an entity lifecycleDB.table(...)
Connections, SQL and transactionsDatabase and DB

DB.table() does not run model casts, accessors, events or scopes. A model builder hydrates entities, but its mass writes also skip each instance’s lifecycle. Choose deliberately when a rule depends on events.

The ORM uses database configuration; it has no separate connection file. A model operation does not automatically make several actions transactional: define the unit with transactions. Python state is not automatically reverted by an SQL rollback; retrieve a fresh instance after rolling back.

A scope constrains a query, an event wraps an instance operation, and soft deletion changes deletion writes and visibility. These mechanisms do not replace authorization or SQL constraints. Verify their interactions with ORM tests.