One of the ORM’s core concepts is expressions, which are composed using functions, operators and model fields. Expressions are used in multiple places in the ORM:
default
, alias
and
materialized
.MergeTree
family.filter
, exclude
, order_by
,
aggregate
and limit_by
.Expressions usually include ClickHouse database functions, which are
made available by the F
class. Here’s a simple
function:
from infi.clickhouse_orm import F
= F.today() expr
Functions that accept arguments can be composed, just like when using SQL:
= F.toDayOfWeek(F.today()) expr
You can see the SQL expression that is represented by an ORM
expression by calling its to_sql
method or converting it to
a string:
>>> print(expr)
toDayOfWeek(today())
ORM expressions support Python’s standard arithmetic operators, so
you can compose expressions using +
, -
,
*
, /
, //
and %
. For
example:
# A random integer between 1 and 10
% 10 + 1 F.rand()
There is also support for comparison operators (<
,
<=
, ==
, >=
,
>
, !=
) and logical operators
(&
, |
, ~
, ^
)
which are often used for filtering querysets:
# Is it Friday the 13th?
== 6) & (F.toDayOfMonth(F.today()) == 13) (F.toDayOfWeek(F.today())
Note that Python’s bitwise operators (&
,
|
, ~
, ^
) have higher precedence
than comparison operators, so always use parentheses when combining
these two types of operators in an expression. Otherwise the resulting
SQL might be different than what you would expect.
To refer to a model field inside an expression, use
<class>.<field>
syntax, for example:
# Convert the temperature from Celsius to Fahrenheit
* 1.8 + 32 Sensor.temperature
Inside model class definitions omit the class name:
class Person(Model):
= Float32Field()
height_cm = Float32Field(alias=height_cm/2.54)
height_inch ...
Some of ClickHouse’s aggregate functions can accept one or more parameters - constants for initialization that affect the way the function works. The syntax is two pairs of brackets instead of one. The first is for parameters, and the second is for arguments. For example:
# Most common last names
5)(Person.last_name)
F.topK(# Find 90th, 95th and 99th percentile of heights
0.9, 0.95, 0.99)(Person.height) F.quantiles(
Since expressions are just Python objects until they get converted to SQL, it is possible to invent new “functions” by combining existing ones into useful building blocks. For example, we can create a reusable expression that takes a string and trims whitespace, converts it to uppercase, and changes blanks to underscores:
def normalize_string(s):
return F.replaceAll(F.upper(F.trimBoth(s)), ' ', '_')
Then we can use this expression anywhere we need it:
class Event(Model):
= StringField()
code = StringField(materialized=normalize_string(code)) normalized_code
ClickHouse has many hundreds of functions, and new ones often get
added. Many, but not all of them, are already covered by the ORM. If you
encounter a function that the database supports but is not available in
the F
class, please report this via a GitHub issue. You can
still use the function by providing its name:
= F("someFunctionName", arg1, arg2, ...) expr
Note that higher-order database functions (those that use lambda expressions) are not supported.
<< Async Databases | Table of Contents | Importing ORM Classes >>