Data transfer objects
The user registration DTO can be an instance of either DataclassDTO, MsgspecDTO or PydanticDTO.
A few constraints are enforced by LitestarUsersConfig at startup:
user_read_dtomust not expose a field namedpassword(plain-text password exposure).user_registration_dtomust not include a field namedpassword_hash(raw hash exposure).user_update_dtomust be partial.LitestarUsersConfigautomatically injectsrename_fields = {"password_hash": "password"}into the update DTO, so that clients sendpassword(notpassword_hash) when changing a user's password. Excludepassword_hashfrom the update DTO only if you intentionally want to disable password changes via that endpoint.
Note
Excluding password_hash from the read DTO is a security best practice - hashed passwords should never be returned to the client. This is not validated automatically.
Example
from dataclasses import dataclass
from advanced_alchemy.extensions.litestar.dto import SQLAlchemyDTO, SQLAlchemyDTOConfig
from litestar.dto import DataclassDTO
from .models import User
@dataclass
class UserRegistrationSchema:
email: str
password: str
class UserRegistrationDTO(DataclassDTO[UserRegistrationSchema]):
"""User registration DTO."""
class UserReadDTO(SQLAlchemyDTO[User]):
# exclude password_hash so the hash is never sent to the client
config = SQLAlchemyDTOConfig(exclude={"password_hash", "login_count"})
class UserUpdateDTO(SQLAlchemyDTO[User]):
# password_hash is NOT excluded here: the framework renames it to `password`
# in the API, allowing users to change their password via this endpoint.
config = SQLAlchemyDTOConfig(exclude={"login_count"}, partial=True)
Role DTOs
When using RBAC, role DTOs are passed directly to RoleManagementHandlerConfig rather than to LitestarUsersConfig:
from advanced_alchemy.extensions.litestar.dto import SQLAlchemyDTO, SQLAlchemyDTOConfig
from .models import Role
class RoleCreateDTO(SQLAlchemyDTO[Role]):
config = SQLAlchemyDTOConfig(exclude={"id"})
class RoleReadDTO(SQLAlchemyDTO[Role]):
pass
class RoleUpdateDTO(SQLAlchemyDTO[Role]):
config = SQLAlchemyDTOConfig(exclude={"id"}, partial=True)
These are then passed as required positional arguments when creating RoleManagementHandlerConfig. See route handler configs for a complete example.