Advanced Usage
Customizing the Generated Model
For most use cases, SQLCrucible's built-in support for ORM descriptors is sufficient. See the ORM Descriptors guide for hybrid_property and association_proxy support.
For advanced customization beyond what's covered there, you can override __sqlalchemy_type__ with a lazyproperty:
from sqlcrucible.entity.core import lazyproperty
from sqlcrucible import SQLCrucibleEntity
def user_sqlalchemy_type(cls: type["User"]):
class CustomModel(cls.__sqlalchemy_automodel__):
def custom_method(self):
return f"Custom: {self.name}"
return CustomModel
class User(SQLCrucibleEntity):
__sqlalchemy_params__ = {"__tablename__": "user"}
name: str
__sqlalchemy_type__ = lazyproperty(user_sqlalchemy_type)
This allows you to add custom methods or any other SQLAlchemy-specific functionality to the generated model.
Reusing Existing SQLAlchemy Models
You can attach a SQLCrucible entity to an existing SQLAlchemy model:
from typing import Annotated
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlcrucible import SQLCrucibleEntity
class Base(DeclarativeBase):
pass
# Your existing SQLAlchemy model
class UserModel(Base):
__tablename__ = "user"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column()
email: Mapped[str] = mapped_column()
# Attach an entity to it
class User(SQLCrucibleEntity):
__sqlalchemy_type__ = UserModel
id: Annotated[int, mapped_column(primary_key=True)]
name: str
email: str
Creating "Views" with Subset of Fields
You can create multiple entity classes that map to the same SQLAlchemy model but expose different fields:
from typing import Annotated
from sqlalchemy.orm import mapped_column
from sqlcrucible import SQLCrucibleEntity
# Full entity with all fields
class User(SQLCrucibleEntity):
__sqlalchemy_type__ = UserModel
id: Annotated[int, mapped_column(primary_key=True)]
name: str
email: str
# Summary view with only some fields
class UserSummary(SQLCrucibleEntity):
__sqlalchemy_type__ = UserModel
id: Annotated[int, mapped_column(primary_key=True)]
name: str
Type Stub Generation
SQLCrucible dynamically generates SQLAlchemy model classes at runtime. While this provides flexibility, Python's type system cannot represent these dynamically-created types — type checkers only see type[Any] for __sqlalchemy_type__, losing all column information.
Type stubs (.pyi files) solve this by providing static type declarations. With generated stubs:
Artist.__sqlalchemy_type__.nameis recognized asInstrumentedAttribute[str]- Invalid column access produces a type error
- IDE autocompletion works for column names
Generating Stubs
# Generate stubs for a module
python -m sqlcrucible.stubs myapp.models
# Multiple modules
python -m sqlcrucible.stubs myapp.models myapp.other_models
# Custom output directory (default: stubs/)
python -m sqlcrucible.stubs myapp.models --output typings/
Tip
For projects with entities spread across many modules, create a single module that imports them all, then generate stubs from that.
Configuring Type Checkers
Keeping Stubs Updated
Regenerate stubs whenever you add or modify entity fields. Consider adding stub generation to your CI process or using a pre-commit hook.