Skip to content

Relationships API

Complete reference for relationship types.

ForeignKey

ForeignKey

Describe a forward foreign-key relationship between models

Attributes:

to: Target model class resolved during model binding.
related_name: Name of the reverse relationship attribute on the target model.
on_delete: Referential action applied when the parent row is deleted.
unique: Treat the relation as one-to-one when True.
index: Request a non-unique index on the shadow ``*_id`` column.
nullable: Alembic nullability for the shadow ``*_id`` column (see
    :class:`FerroField` ``nullable``). When ``'infer'``, uses whether the
    **relation** annotation allows ``None``.

Examples:

>>> from typing import Annotated
>>> from ferro.models import Model
>>>
>>> class User(Model):
...     id: Annotated[int, FerroField(primary_key=True)]
>>>
>>> class Post(Model):
...     id: Annotated[int, FerroField(primary_key=True)]
...     author: Annotated[int, ForeignKey("posts", on_delete="CASCADE")]

Attributes

to = None instance-attribute
related_name = related_name instance-attribute
on_delete = on_delete instance-attribute
unique = unique instance-attribute
index = index instance-attribute
nullable = _validate_nullable_option(nullable, 'ForeignKey') instance-attribute
relation_annotation = None instance-attribute

Functions

__init__(related_name, on_delete='CASCADE', unique=False, index=False, nullable='infer')

Initialize foreign-key relationship metadata

Args:

related_name: Name for reverse access from the related model.
on_delete: Referential action for parent deletion.
    Common values include "CASCADE", "RESTRICT", "SET NULL", "SET DEFAULT", and "NO ACTION".
unique: Set to True to enforce one-to-one behavior. Implies an
    index, so combining ``unique=True`` with ``index=True`` is
    redundant; ``index=True`` will be ignored and a ``UserWarning``
    will be raised.
index: Set to True to create a non-unique index on the shadow
    ``*_id`` column. Useful for tenant FKs queried on every list
    endpoint where Postgres does not auto-index the FK column.
nullable: See :class:`ForeignKey` class docstring.

Examples:

>>> from typing import Annotated
>>> from ferro import BackRef, ForeignKey, Relation
>>> from ferro.models import Model
>>>
>>> class Org(Model):
...     id: Annotated[int, FerroField(primary_key=True)]
...     projects: Relation[list["Project"]] = BackRef()
>>>
>>> class Project(Model):
...     id: Annotated[int, FerroField(primary_key=True)]
...     org: Annotated[Org, ForeignKey("projects", index=True)]

Relation

Relation

Bases: Query[T]

Represent lazy collection relationship queries with typing support

Examples:

>>> class User(Model):
...     id: Annotated[int, FerroField(primary_key=True)]
...     name: str
...     posts: Relation[list["Post"]] = BackRef()
>>> class Post(Model):
...     id: Annotated[int, FerroField(primary_key=True)]
...     title: str
...     user: Annotated[User, ForeignKey(related_name="posts")]
>>> user = await User.get(1)
>>> posts = await user.posts.all()
>>> isinstance(posts, list)
True

Functions

where(node)
where(node: QueryNode) -> Relation[T]
where(node: Predicate[T]) -> Relation[T]
order_by(field, direction='asc')
limit(value)
offset(value)
all() async
all() -> list[E]
all() -> list[E]
first() async
first() -> E | None
first() -> E | None
__get_pydantic_core_schema__(_source_type, _handler) classmethod

Allow pydantic-core to treat relationships as arbitrary runtime values

BackRef

BackRef

Declare a reverse relationship field.

BackRef() is a convenience wrapper around Field(back_ref=True).

Functions

__new__(**kwargs)
__class_getitem__(_item) classmethod

ManyToMany

ManyToMany(*, related_name, through=None, reverse_index=True, **kwargs)

Declare a many-to-many relationship field.

Parameters:

Name Type Description Default
related_name str

Name for reverse access from the related model.

required
through str | None

Optional explicit join table name. When omitted, Ferro generates a join table name automatically.

None
reverse_index bool

When True (default), the synthesized join table gets a non-unique composite index on (target_col, source_col) to optimize back-ref queries. Set to False to opt out.

True

See Also