Database models
The user model
The SQLAlchemyUserMixin provides the following columns:
email: strpassword_hash: stris_active: boolis_verified: bool
SQLAlchemy User
Important
Litestar-Users is reliant on the SQLAlchemyInitPlugin for session management and dependency injection, this ensures that no more than one SQLAlchemy session is spun up per request lifecycle.
from advanced_alchemy.base import UUIDBase
from litestar_users.mixins import SQLAlchemyUserMixin
class User(UUIDBase, SQLAlchemyUserMixin):
"""User model."""
The user model can be extended arbitrarily:
from advanced_alchemy.base import UUIDBase
from litestar_users.mixins import SQLAlchemyUserMixin
from sqlalchemy import Integer
from sqlalchemy.orm import Mapped, mapped_column
class User(UUIDBase, SQLAlchemyUserMixin):
"""User model."""
token_count: Mapped[int] = mapped_column(Integer())
Note
You can skip the next section if you're not making use of Litestar User's built in RBAC.
The role model
For RBAC (role based access control), additionally set up a Role model along with a user-role association table.
Note
You must define your own User.roles relationship and association table, as these depend on your own __tablename__ definitions.
SQLAlchemy Role
Use a Core Table for the association so that no extra ORM entity is introduced:
from advanced_alchemy.base import UUIDBase, orm_registry
from litestar_users.mixins import SQLAlchemyUserMixin, SQLAlchemyRoleMixin
from sqlalchemy import Column, ForeignKey, Table
from sqlalchemy.orm import Mapped, relationship
user_role = Table(
"user_role",
orm_registry.metadata,
Column("user_id", ForeignKey("user.id", ondelete="CASCADE"), primary_key=True),
Column("role_id", ForeignKey("role.id", ondelete="CASCADE"), primary_key=True),
)
class Role(UUIDBase, SQLAlchemyRoleMixin):
"""Role model."""
class User(UUIDBase, SQLAlchemyUserMixin):
"""User model."""
roles: Mapped[list[Role]] = relationship(secondary="user_role", lazy="selectin")
Just as with the user model, you can define arbitrary custom columns on Role:
from datetime import datetime
from advanced_alchemy.base import UUIDBase
from litestar_users.mixins import SQLAlchemyRoleMixin
from sqlalchemy import DateTime
from sqlalchemy.orm import Mapped, mapped_column
class Role(UUIDBase, SQLAlchemyRoleMixin):
created_at: Mapped[datetime] = mapped_column(DateTime(), default=datetime.now)
Note
You can skip the next section if you're not making use of Litestar Users with OAuth2.
The OAuth account model
For OAuth2, set up an OAuthAccount model with a foreign key back to the user.
SQLAlchemy OAuth Account
from uuid import UUID
from advanced_alchemy.base import UUIDBase
from litestar_users.mixins import (
SQLAlchemyOAuthAccountMixin,
SQLAlchemyUserMixin,
)
from sqlalchemy import ForeignKey, Uuid
from sqlalchemy.orm import Mapped, mapped_column, relationship
class OAuthAccount(UUIDBase, SQLAlchemyOAuthAccountMixin):
"""OAuth account model."""
user_id: Mapped[UUID] = mapped_column(Uuid(), ForeignKey("user.id"))
class User(UUIDBase, SQLAlchemyUserMixin):
"""User model."""
oauth_accounts: Mapped[list[OAuthAccount]] = relationship(
OAuthAccount, lazy="selectin"
)
Repositories
Litestar-Users no longer ships its own repository classes. Instead, you subclass SQLAlchemyAsyncRepository from advanced-alchemy and set model_type as a class variable. The plugin will instantiate the repository on every request.
from advanced_alchemy.repository import SQLAlchemyAsyncRepository
from .models import OAuthAccount, Role, User
class UserRepository(SQLAlchemyAsyncRepository[User]):
model_type = User
class RoleRepository(SQLAlchemyAsyncRepository[Role]):
model_type = Role
class OAuthAccountRepository(SQLAlchemyAsyncRepository[OAuthAccount]):
model_type = OAuthAccount
Pass these classes to LitestarUsersConfig:
user_repository_class- required for all setups.oauth_account_repository_class- required when using OAuth2.role_repository_class- passed insideRoleManagementHandlerConfigwhen using RBAC.