Pythonic policies (ExpressionPolicy)
ExpressionPolicy composes a predicate from SQLAlchemy Core expressions — the analog of
django-rls's ModelPolicy(filters=Q(...)).
Owner or public
from flask_rls import ExpressionPolicy, RLS
from sqlalchemy import column, true
rls.register(
"project",
ExpressionPolicy(
"project_access",
expr=(column("owner_id") == RLS.user_id()) | (column("is_public") == true()),
),
)
Compiles to:
owner_id = (SELECT NULLIF(current_setting('rls.user_id', true), '')::text)
OR is_public = true
Combining tenant and status
from sqlalchemy import column, and_
ExpressionPolicy(
"active_tenant_rows",
expr=and_(
column("tenant_id") == RLS.tenant_id(),
column("status") != "archived",
),
)
Context references
RLS.tenant_id() and RLS.user_id() return SQLAlchemy elements that read the corresponding
GUC. Both accept a cast:
column("tenant_id") == RLS.tenant_id(cast="uuid")
Why it's safer than raw SQL
The expression is compiled by SQLAlchemy's own PostgreSQL dialect, so column identifiers are
quoted and literal values are rendered by the dialect rather than by string concatenation.
Prefer ExpressionPolicy over CustomPolicy whenever your predicate can be expressed with
SQLAlchemy Core.