pub trait Model:
Sized
+ Send
+ Sync
+ Unpin
+ 'static {
type PrimaryKey: PrimaryKey;
Show 15 associated constants and 1 method
const NAME: &'static str;
const TABLE: &'static str;
const FIELDS: &'static [FieldSpec];
const APP_LABEL: &'static str = "app";
const DISPLAY: &'static str = Self::NAME;
const ICON: &'static str = "database";
const DATABASE: Option<&'static str> = None;
const SINGLETON: bool = false;
const SOFT_DELETE: bool = false;
const UNIQUE_TOGETHER: &'static [&'static [&'static str]] = _;
const INDEXES: &'static [&'static [&'static str]] = _;
const ORDERING: &'static [(&'static str, bool)] = _;
const M2M_RELATIONS: &'static [M2MRelationSpec] = _;
const REVERSE_FK_RELATIONS: &'static [ReverseFkRelationSpec] = _;
const ONE_TO_ONE_RELATIONS: &'static [OneToOneRelationSpec] = _;
// Required method
fn primary_key(&self) -> Self::PrimaryKey;
}Expand description
The trait every model implements.
Read at runtime to build queries (T::TABLE, T::FIELDS), at boot
to validate field/backend compatibility (M4), and at migration time
to diff against the last snapshot (M5).
Model is metadata-only — it carries no row-materialization bound.
QuerySet terminals add for<'r> FromRow<'r, R> for the row type
they need at the call site (sqlite or postgres). User structs pick
up both impls via a single #[derive(sqlx::FromRow)] because
sqlx’s derive emits a generic-over-R impl.
Required Associated Constants§
Sourceconst NAME: &'static str
const NAME: &'static str
The struct name, used by the migration engine (M5) to label snapshot entries and to map autodetected operations back to the model that produced them. The M3 derive emits the struct ident verbatim (“Post”, “Comment”, etc.).
Sourceconst TABLE: &'static str
const TABLE: &'static str
The SQL table name. M3’s derive defaults this to the
snake_case of the struct name unless #[umbral(table = "...")]
overrides it.
Sourceconst FIELDS: &'static [FieldSpec]
const FIELDS: &'static [FieldSpec]
Static metadata for every field on the model.
One FieldSpec per field, in declaration order. Read by the
QuerySet (to build the SELECT column list), by the system check
(M4) for field/backend compatibility, and by the migration
engine (M5) for snapshot diffing.
Provided Associated Constants§
Sourceconst APP_LABEL: &'static str = "app"
const APP_LABEL: &'static str = "app"
The app label (the owning plugin’s name) this model belongs to.
Sourced from #[umbral(plugin = "...")]; defaults to "app" (the
registry’s default key) when the attribute is absent. Authoritative
for permission codenames (gaps2 #80g): umbral-permissions reads this
to build <app_label>.<verb>_<model> codenames, instead of splitting
the table name at the first _ (which collided distinct models).
Sourceconst DISPLAY: &'static str = Self::NAME
const DISPLAY: &'static str = Self::NAME
Human-readable display name for this model, used by the admin
sidebar as the default label. Defaults to Self::NAME.
Override via #[umbral(display = "Users")] on the struct.
Sourceconst ICON: &'static str = "database"
const ICON: &'static str = "database"
Lucide icon slug shown next to this model in the admin sidebar.
Defaults to "database". Any valid Lucide icon name works; unknown
names are silently ignored by Lucide at render time.
Override via #[umbral(icon = "users")] on the struct.
Sourceconst DATABASE: Option<&'static str> = None
const DATABASE: Option<&'static str> = None
Database alias this model lives on, when the app registers more
than one pool via AppBuilder::database(...). None (the
default) means “use whatever the owning plugin chose via
Plugin::database(), or \"default\" if neither side
overrode.”
Override via #[umbral(database = "analytics")] on the struct.
Per-model wins over per-plugin — useful for a single plugin
that owns one model on the primary DB and another on an
archive/analytics DB.
Sourceconst SINGLETON: bool = false
const SINGLETON: bool = false
Single-row-marker. When true, the admin auto-redirects the
list view to the (sole) row’s edit form, hides the “+ New”
button, and surfaces the model as a settings-style screen.
The single-row settings model pattern. Set via
#[umbral(singleton)] on the struct. Closes BUG-9 in
bugs/tests/testBugs.md.
Default false. Default-row seeding (so the first admin
visit doesn’t 404) is the user’s responsibility — typically
a one-liner in Plugin::on_ready that calls
T::objects().create(T::default()).await if the count is
zero. A future framework helper could automate that; for v1
the trait const is enough to let admin and any third-party
tool know the model is singleton-shaped.
Sourceconst SOFT_DELETE: bool = false
const SOFT_DELETE: bool = false
Feature #72 — soft-delete marker. Set via
#[umbral(soft_delete)] on the struct. When true, the
framework treats this model as having a deleted_at: Option<DateTime<Utc>> column (which the user MUST declare
— derive macros can’t add fields to the input struct), and:
- Every
QuerySet<T>terminal auto-injectsWHERE deleted_at IS NULLso soft-deleted rows are invisible by default. Manager::delete_instance(&row)andQuerySet::delete()issueUPDATE table SET deleted_at = NOW() WHERE ...instead of a hardDELETE FROM table WHERE ....- Callers who actually want the soft-deleted rows (admin
trash views, audit dumps, undelete flows) opt back in
per-query via
.with_deleted()or.only_deleted(). - Callers who need a hard DELETE (GDPR purge, etc.) use
.hard_delete()to bypass the soft path on a per-call basis.
Default false so existing models compile unchanged.
Sourceconst UNIQUE_TOGETHER: &'static [&'static [&'static str]] = _
const UNIQUE_TOGETHER: &'static [&'static [&'static str]] = _
Composite-UNIQUE constraints. Each inner slice names a
constraint over the listed column names. Set via
#[umbral(unique_together = [["a", "b"]])]. Closes BUG-6 in
bugs/tests/testBugs.md. Default empty; the migration engine
emits one UNIQUE (col1, col2) clause per inner group on
CREATE TABLE.
Sourceconst INDEXES: &'static [&'static [&'static str]] = _
const INDEXES: &'static [&'static [&'static str]] = _
Multi-column indexes. Each inner slice names an index over
the listed columns. Set via
#[umbral(indexes = [["tenant_id", "created_at"]])]. Closes
BUG-7. Default empty; the migration engine emits
CREATE INDEX IF NOT EXISTS idx_<table>_<col1>_<col2> after
the CREATE TABLE. Single-column indexes stay on the field
attribute (#[umbral(index)]).
Sourceconst ORDERING: &'static [(&'static str, bool)] = _
const ORDERING: &'static [(&'static str, bool)] = _
Default ORDER BY clause, applied when a QuerySet terminates
without an explicit order_by. Each tuple is (column_name, is_descending). Set via
#[umbral(ordering = ["-published_at", "id"])] (leading -
flips to DESC). Closes BUG-8. Default empty.
Sourceconst M2M_RELATIONS: &'static [M2MRelationSpec] = _
const M2M_RELATIONS: &'static [M2MRelationSpec] = _
Many-to-many relations declared on this model. Each entry names a field and its target model. The migration engine uses this to auto-generate junction tables; the admin uses it to render M2M pickers. Default empty.
Sourceconst REVERSE_FK_RELATIONS: &'static [ReverseFkRelationSpec] = _
const REVERSE_FK_RELATIONS: &'static [ReverseFkRelationSpec] = _
Gap #44 — reverse-FK collections declared on this model via
#[umbral(reverse_fk = "<fk_col>")] pub <name>: ReverseSet<C>.
Each entry tells prefetch_related how to fetch the children:
SELECT * FROM <target_table> WHERE <fk_column> IN (parent_pks)
then group by <fk_column> value, populate each parent’s
ReverseSet.resolved. Default empty; the macro emits one
entry per declared ReverseSet<C> field.
Sourceconst ONE_TO_ONE_RELATIONS: &'static [OneToOneRelationSpec] = _
const ONE_TO_ONE_RELATIONS: &'static [OneToOneRelationSpec] = _
Reverse OneToOne accessors declared on this model via
pub <name>: OneToOne<C> (no umbral attribute required).
Unlike REVERSE_FK_RELATIONS, the FK column on the child is
not named at macro time — prefetch_related looks it up at
runtime by scanning the child’s FIELDS for the UNIQUE FK
pointing back at this model’s table. Exactly one match
required; 0 or 2+ matches surface a loud error naming the
ambiguity.
Required Associated Types§
Sourcetype PrimaryKey: PrimaryKey
type PrimaryKey: PrimaryKey
The primary-key type. M2 supports i64 only; UUID lands later.
Required Methods§
Sourcefn primary_key(&self) -> Self::PrimaryKey
fn primary_key(&self) -> Self::PrimaryKey
Return the primary key of this instance.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".