SmartQueryMixin
The SmartQueryMixin
class provides advanced query functionality for SQLAlchemy
models, allowing you to filter, sort, and eager load data in a single query,
making it easier to retrieve specific data from the database.
It uses the InspectionMixin
class functionality.
Info
This mixin is intended to extend the functionality of the
ActiveRecordMixin
on which the examples below are based. It is not intended to be used on its own.
Table of Contents
Core Features
Smart Queries
Smart queries allow you to filter, sort, and eager load data in a single query.
users = await User.smart_query(
criterion=(User.age >= 18,),
filters={'name__like': '%Bob%'},
sort_columns=(User.username,),
sort_attrs=['-created_at'],
schema={User.posts: 'joined'}
).all()
Filtering
You can filter data using native SQLAlchemy filter expressions.
Also, you can filter data using Django-like filter expressions.
Sorting
You can sort data using native SQLAlchemy sort expressions with
the sort_columns
parameter.
Also, you can sort data using Django-like sort expressions with
the sort_attrs
parameter.
Eager Loading
You can eager load relationships using various loading strategies
with the schema
parameter.
API Reference
The SmartQueryMixin
class provides three low-level methods for building filter, sort
and eager load expressions:
filter_expr
: Builds filter expressions.order_expr
: Builds order expressions.eager_expr
: Builds eager load expressions.
Warning
All relations used in filtering/sorting should be explicitly set,
not just being a backref
.
This is because sqlactive
does not know the relation direction and cannot
infer it.
So, when defining a relationship like:
It is required to define the reverse relationship:
filter_expr
Takes keyword arguments like
and returns list of expressions likeInfo
When using alias, for example:
the query cannot be executed like
because it will be compiled to
which is wrong. The select is made from
product_1
but filter is based onproduct
. Such filter will not work.
A correct way to execute such query isFor such case,
filter_expr
can be called ON ALIAS:Parameters:
filters
: Django-style filters.Returns:
list[sqlalchemy.sql.elements.BinaryExpression]
: List of filter expressions.Raises:
KeyError
:
- If operator is not found in
_operators
.- If attribute is not found in
filterable_attributes
property.Example:
db.query(Product).filter( *Product.filter_expr(age_from=5, subject_ids__in=[1, 2])) # will compile to WHERE age_from = 5 AND subject_ids IN [1, 2] filters = {'age_from': 5, 'subject_ids__in': [1,2]} db.query(Product).filter(*Product.filter_expr(**filters)) # will compile to WHERE age_from = 5 AND subject_ids IN [1, 2]
order_expr
Takes list of columns to order by like
and returns list of expressions likeParameters:
columns
: Django-style columns.Returns:
list[sqlalchemy.sql.elements.UnaryExpression]
: List of sort expressions.Raises:
KeyError
: If attribute is not sortable.Example:
eager_expr
def eager_expr(
schema: dict[InstrumentedAttribute, str | tuple[str, dict[InstrumentedAttribute, Any]] | dict]
)
Takes schema like
and returns eager loading expressions likeschema = { Post.user: JOINED, # joinedload user Post.comments: (SUBQUERY, { # load comments in separate query Comment.user: JOINED # but, in this separate query, join user }) }
Parameters:
schema
: Eager loading schema.Returns:
list[sqlalchemy.orm.strategy_options._AbstractLoad]
: List of eager loading expressions.Example: