Skip to content

Model API

Complete reference for the Model base class and related methods.

Model

Bases: BaseModel

Provide the base class for all Ferro models

Inheriting from this class registers schema metadata with the Rust core and exposes high-performance CRUD and query entrypoints.

Composite unique constraints: declare a typing.ClassVar named __ferro_composite_uniques__ as a tuple of tuples of column names (for example (("user_id", "org_id"),)) to enforce uniqueness on those columns together. This is separate from per-column uniqueness (Field(unique=True) on the field, Annotated[..., Field(unique=True)], or Annotated[..., FerroField(unique=True)]), each of which applies to a single column only. Default many-to-many join tables get a composite unique on their two foreign-key columns automatically.

Composite indexes: declare a typing.ClassVar named __ferro_composite_indexes__ as a tuple of tuples of column names (for example (("user_id", "created_at"),)) for non-unique multi-column indexes. Validation rules mirror __ferro_composite_uniques__: each inner tuple must contain at least two columns, columns must exist on the model, and order is preserved (matters for leftmost-prefix optimization). For single-column indexes use Field(index=True). Default many-to-many join tables get a non-unique reverse-direction composite index automatically; opt out with ManyToMany(reverse_index=False).

Examples:

>>> class User(Model):
...     id: int | None = None
...     name: str

Functions

create(**fields) async classmethod

Create and persist a new model instance

Parameters:

Name Type Description Default
**fields

Field values to construct the model.

{}

Returns:

Type Description
Self

The newly created and persisted model instance.

Examples:

>>> user = await User.create(name="Taylor")
>>> isinstance(user, User)
True

bulk_create(instances, *, using=None) async classmethod

Persist multiple instances in a single bulk operation

Parameters:

Name Type Description Default
instances list[Self]

Model instances to persist.

required

Returns:

Type Description
int

The number of records inserted.

Examples:

>>> rows = await User.bulk_create([User(name="A"), User(name="B")])
>>> isinstance(rows, int)
True

get(pk) async classmethod

Fetch one record by primary key value.

Parameters:

Name Type Description Default
pk Any

Primary key value to fetch a single record.

required

Returns:

Type Description
Self

The matching model instance.

Raises:

Type Description
ModelDoesNotExist

When no row exists for this primary key. Use :meth:get_or_none if you need optional lookup without raising.

Examples:

>>> user = await User.get(1)
>>> isinstance(user, User)
True

get_or_none(pk) async classmethod

Fetch one record by primary key, or return None if no row exists.

Parameters:

Name Type Description Default
pk Any

Primary key value to fetch a single record.

required

Returns:

Type Description
Self | None

The matching model instance, or None when no record exists.

where(node) classmethod

where(node: QueryNode) -> Query[Self]
where(node: Predicate[Self]) -> Query[Self]

Start a fluent query with an initial condition.

Accepts either a :class:QueryNode (built with operator syntax or with :func:ferro.query.col) or a lambda predicate of shape Callable[[QueryProxy[Self]], QueryNode]. See docs/concepts/query-typing.md for the trade-offs between the three styles.

Parameters:

Name Type Description Default
node QueryNode | Predicate[Self]

A QueryNode or a predicate callable.

required

Returns:

Type Description
Query[Self]

A query object scoped to this model class.

Examples:

>>> q1 = User.where(User.id == 1)
>>> q2 = User.where(lambda t: t.archived == False)  # noqa: E712
>>> isinstance(q1, Query) and isinstance(q2, Query)
True

select() classmethod

Start an empty fluent query for this model class

Returns:

Type Description
Query[Self]

A query object scoped to this model class.

Examples:

>>> query = User.select().limit(5)
>>> isinstance(query, Query)
True

all(*, using=None) async classmethod

Fetch all records for this model class

Returns:

Type Description
list[Self]

A list of hydrated model instances.

Examples:

>>> users = await User.all()
>>> isinstance(users, list)
True

delete(*, using=None) async

Delete the current model instance from storage

Returns:

Type Description
None

None

Examples:

>>> user = await User.get_or_none(1)
>>> if user:
...     await user.delete()

save(*, using=None) async

Persist the current model instance

Returns:

Type Description
None

None

Examples:

>>> user = User(name="Taylor")
>>> await user.save()

refresh(*, using=None) async

Reload this instance from storage using its primary key

Returns:

Type Description
None

None

Raises:

Type Description
RuntimeError

If no primary key is available or the record no longer exists.

Examples:

>>> user = await User.get(1)
>>> await user.refresh()

See Also