flask_more_smorest.perms.model_mixins

Reusable mixins for User models and other models in Flask-More-Smorest.

Classes

HasUserMixin()

Adds user_id foreign key and user relationship to a model.

ProfileMixin()

Adds profile fields: first_name, last_name, display_name, avatar_url.

SoftDeleteMixin()

Soft delete with deleted_at timestamp and helper methods.

TimestampMixin()

Adds authentication-related timestamps: last_login_at, email_verified_at.

UserOwnershipMixin()

User-owned resources with configurable permission delegation.

class flask_more_smorest.perms.model_mixins.HasUserMixin[source]

Adds user_id foreign key and user relationship to a model.

Configuration:
  • __user_field_name__: Custom alias for user_id (default: “user_id”)

  • __user_relationship_name__: Custom alias for user (default: “user”)

  • __user_id_nullable__: Allow NULL owner IDs (default: False)

  • __user_backref_name__: Custom backref on User model
    • None (default): Auto-generate as {tablename}s (e.g., “articles”)

    • Custom string: Use specified name

    • "": Skip backref creation

Example

>>> class Article(BasePermsModel, HasUserMixin):
...     __user_backref_name__ = "written_articles"
...     title: Mapped[str] = mapped_column(sa.String(200))
>>> user.written_articles  # Custom backref
classmethod __init_subclass__(**kwargs)[source]

Configure user field and relationship aliases on subclass creation.

user_id = <sqlalchemy.orm.properties.MappedColumn object>
user

Relationship to the registered User model.

Uses lazy resolution via lambda to support custom User models registered through init_fms(). The lambda is evaluated during mapper configuration, allowing get_user_model() to return the correct registered User class.

class flask_more_smorest.perms.model_mixins.UserOwnershipMixin[source]

User-owned resources with configurable permission delegation.

Two modes:

  1. Simple Ownership (default, __delegate_to_user__ = False): - Compares user_id == current_user.id - Use for: Notes, posts, comments

  2. Delegated Permissions (__delegate_to_user__ = True): - Calls self.user._can_write(current_user) - Use for: Tokens, settings, API keys

__delegate_to_user__

Delegate to user’s permission methods (default: False)

__user_id_nullable__

Allow NULL owner IDs (default: False)

Example

>>> class Token(UserOwnershipMixin, BasePermsModel):
...     __delegate_to_user__ = True
...     token: Mapped[str] = mapped_column(sa.String(500))
>>> # Delegates to user's permission methods
class flask_more_smorest.perms.model_mixins.TimestampMixin[source]

Adds authentication-related timestamps: last_login_at, email_verified_at.

last_login_at: Mapped[datetime | None] = <sqlalchemy.orm.properties.MappedColumn object>
email_verified_at: Mapped[datetime | None] = <sqlalchemy.orm.properties.MappedColumn object>
class flask_more_smorest.perms.model_mixins.ProfileMixin[source]

Adds profile fields: first_name, last_name, display_name, avatar_url.

Property: full_name returns combined first/last name.

first_name: Mapped[str | None] = <sqlalchemy.orm.properties.MappedColumn object>
last_name: Mapped[str | None] = <sqlalchemy.orm.properties.MappedColumn object>
display_name: Mapped[str | None] = <sqlalchemy.orm.properties.MappedColumn object>
avatar_url: Mapped[str | None] = <sqlalchemy.orm.properties.MappedColumn object>
property full_name: str

Get formatted full name.

Returns:

Full name as “first last”, or just first or last if one is missing

classmethod parse_full_name(full_name)[source]

Parse a full name into first and last name components.

Strips leading/trailing whitespace and splits on first space. Everything after the first space is considered the last name.

Parameters:

full_name (str) – The full name string

Return type:

dict[str, str]

Returns:

Dictionary with ‘first_name’ and ‘last_name’ keys

property avatar: str | None

Get avatar URL (alias for avatar_url).

Override this property to implement custom avatar logic (e.g., generating Gravatar or Initials avatar if avatar_url is missing).

class flask_more_smorest.perms.model_mixins.SoftDeleteMixin[source]

Soft delete with deleted_at timestamp and helper methods.

Methods: soft_delete() marks as deleted, restore() clears. Property: is_deleted returns True if deleted_at is not None.

deleted_at: Mapped[datetime | None] = <sqlalchemy.orm.properties.MappedColumn object>
property is_deleted: bool

Check if record is soft deleted.

Returns:

True if record has been soft deleted

soft_delete()[source]

Mark record as soft deleted.

Sets deleted_at to current time and optionally disables the record if is_enabled field exists.

Return type:

None

restore()[source]

Restore soft deleted record.

Clears deleted_at and optionally re-enables the record if is_enabled field exists.

Return type:

None