Bind ORM models and column_map¶
SQLRules binds each constrained field to a SQLAlchemy column. By default it
looks up columns on the object you pass as table (a Table, selectable, or
ORM class/entity). Use column_map when names differ or binding is ambiguous.
Table (default)¶
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy import Column, Integer, MetaData, String, Table
import sqlrules
users = Table(
"users",
MetaData(),
Column("age", Integer),
Column("full_name", String),
)
class UserFilter(BaseModel):
age: Annotated[int, Field(ge=18)]
name: Annotated[str, Field(min_length=1, alias="full_name")]
# String Field aliases are tried before the Python field name.
rules = sqlrules.compile(UserFilter, users)
Explicit column_map¶
Pass a map from Python field name or alias string to a column element when automatic lookup fails (joined tables, renamed columns, hybrid attributes):
rules = sqlrules.compile(
UserFilter,
users,
column_map={
"age": users.c.age,
"full_name": users.c.full_name, # alias used on the Field
},
)
Declarative ORM¶
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
age: Mapped[int]
name: Mapped[str]
class UserFilter(BaseModel):
age: Annotated[int, Field(ge=18)]
name: Annotated[str, Field(min_length=2)]
rules = sqlrules.compile(UserFilter, User)
stmt = User.__table__.select().where(*sqlrules.where(rules))
If an ORM attribute is not a real column (relationship, hybrid), pass that
field through column_map to the underlying column, or you will get
MissingColumnError.
Tips¶
Rule dict keys are always Python field names, not aliases.
Unconstrained supported-type fields are omitted and do not need a column.
See Troubleshooting for
MissingColumnError.