Query Builder - Usage guide¶
All available operators¶
General operators¶
| Operator | Description |
|---|---|
= | Equal to |
!= | Not equal to |
< | Less than |
<= | Less than or equal |
> | Greater than |
>= | Greater than or equal |
between | Between two values |
like | SQL LIKE pattern matching |
ilike | SQL LIKE pattern matching (case insensitive) |
not like | SQL NOT LIKE pattern matching |
not ilike | SQL NOT LIKE pattern matching (case insensitive) |
starts with | Starts with text |
ends with | Ends with text |
not starts with | Does not start with text |
not ends with | Does not end with text |
contains | Contains text (case sensitive) |
icontains | Contains text (case insensitive) |
not contains | Does not contain text (case sensitive) |
not icontains | Does not contain text (case insensitive) |
match | Full-text search match |
in | Value is in list |
not in | Value is not in list |
is true | Boolean field is true |
is false | Boolean field is false |
is empty | Field is null or empty |
is not empty | Field has a value |
any | The relation carries a record matching the sub-filter |
not any | The relation carries no record matching the sub-filter |
Vector field operators¶
| Operator | Description |
|---|---|
l1 distance | L1/Manhattan distance |
l1 distance < | L1 distance less than |
l1 distance <= | L1 distance less than or equal |
l1 distance > | L1 distance greater than |
l1 distance >= | L1 distance greater than or equal |
l2 distance | L2/Euclidean distance |
l2 distance < | L2 distance less than |
l2 distance <= | L2 distance less than or equal |
l2 distance > | L2 distance greater than |
l2 distance >= | L2 distance greater than or equal |
cosine distance | Cosine distance |
cosine distance < | Cosine distance less than |
cosine distance <= | Cosine distance less than or equal |
cosine distance > | Cosine distance greater than |
cosine distance >= | Cosine distance greater than or equal |
inner product | Inner product |
inner product < | Inner product less than |
inner product <= | Inner product less than or equal |
inner product > | Inner product greater than |
inner product >= | Inner product greater than or equal |
Spatial field operators¶
| Operator | Description |
|---|---|
spatial distance | Calculate spatial distance between points |
spatial distance < | Spatial distance less than |
spatial distance <= | Spatial distance less than or equal |
spatial distance > | Spatial distance greater than |
spatial distance >= | Spatial distance greater than or equal |
spatial within distance | Point within specified distance |
spatial contains | Geometry contains another geometry |
spatial within | Geometry within another geometry |
spatial intersects | Geometries intersect |
spatial equals | Geometries are equal |
spatial disjoint | Geometries are disjoint |
spatial touches | Geometries touch |
spatial crosses | Geometries cross |
spatial overlaps | Geometries overlap |
Filter syntax¶
# Simple rule: ["field", "operator", "value"]
GET /api/products/
X-Filter: ["name", "=", "Laptop"]
# AND conditions: ["&", [rule1, rule2, ...]]
GET /api/products/
X-Filter: ["&", [["price", ">=", 100], ["is_active", "is true"]]]
# OR conditions: ["|", [rule1, rule2, ...]]
GET /api/products/
X-Filter: ["|", [["category", "=", "electronics"], ["category", "=", "books"]]]
Available operators¶
CharField, TextField¶
Operators: =, !=, like, ilike, not like, not ilike, starts with, ends with, not starts with, not ends with, contains, icontains, not contains, not icontains, match, in, not in, is empty, is not empty
Example:
IntegerField, FloatField, DecimalField¶
Operators: =, !=, <, <=, >, >=, between, in, not in, is empty, is not empty
Example:
BooleanField¶
Operators: is true, is false
Example:
DateField, DateTimeField¶
Operators: =, !=, <, <=, >, >=, between, is empty, is not empty
Example:
ChoiceField¶
Operators: =, !=, in, not in, is empty, is not empty
Example:
ForeignKey, OneToOne¶
Operators: =, !=, in, not in, is empty, is not empty, any, not any
Example:
ManyToMany, OneToMany¶
Operators: in, not in, is empty, is not empty, any, not any
Example:
UUIDField¶
Operators: =, !=, like, ilike, not like, not ilike, starts with, ends with, not starts with, not ends with, contains, icontains, not contains, not icontains, match, in, not in, is empty, is not empty
Example:
VectorField¶
Operators: l1 distance, l1 distance <, l1 distance <=, l1 distance >, l1 distance >=, l2 distance, l2 distance <, l2 distance <=, l2 distance >, l2 distance >=, cosine distance, cosine distance <, cosine distance <=, cosine distance >, cosine distance >=, inner product, inner product <, inner product <=, inner product >, inner product >=
Example:
PointField¶
Operators: spatial distance, spatial distance <, spatial distance <=, spatial distance >, spatial distance >=, spatial within distance, spatial contains, spatial within, spatial intersects, spatial equals, spatial disjoint, spatial touches, spatial crosses, spatial overlaps, is empty, is not empty
Examples:
# Find stores within 5km of a point (longitude, latitude)
GET /api/stores/
X-Filter: ["location", "spatial within distance", [[2.3522, 48.8566], 5000]]
# Find stores at exact location
GET /api/stores/
X-Filter: ["location", "spatial equals", [2.3522, 48.8566]]
# Find stores within a specific distance
GET /api/stores/
X-Filter: ["location", "spatial distance <", [[2.3522, 48.8566], 10000]]
Note: Distance operators require a tuple with the reference point and distance value: [[longitude, latitude], distance_in_meters]
Filtering on a relation¶
Two rules over the same relation are independent, each satisfied by a related record of its own: A & B is the intersection of A and B, whatever rules sit next to them. This product matches as soon as it carries a red tag and an urgent tag, the same one or not:
any is the other reading: a single related record satisfying a whole sub-filter. Its value is a filter of the model the relation reaches, written against that model's own fields:
GET /api/products/
X-Filter: ["tags", "any", ["&", [["color", "=", "red"], ["name", "=", "urgent"]]]]
not any negates it, and a record carrying nothing related satisfies it:
An empty sub-filter asks only what the relation carries, so ["tags", "any", null] reads as is not empty and ["tags", "not any", null] as is empty (the short forms read better, and stay).
Named alone, a relation that fans out compares the key of its related records: ["tags", "in", [1, 2]] is ["tags.id", "in", [1, 2]], and so are not in, is empty and is not empty.
A reverse relation is filtered on by the name its foreign key declares with related_name. The name Edgy makes up when none is declared (<model>s_set) is refused, in the API as in the code, as it stays out of the API schemas.
A path crosses at most filter_max_depth relations (8 by default), those leading to the sub-filter it sits in counted: ["category", "any", ["products.tags.name", "=", "red"]] crosses three. A relation and its inverse come back to where they started, so nothing else ends a path that walks them in turn; one going deeper is refused with a 422.
A path only crosses the rows the request could read through the model it reaches: in a workspace, that workspace and the rows keyed to it by their workspace, then what the global filters of the model let through. An any block, an or branch and an ordering on a relation that fans out cross the same rows. global_query, and a rule allowed to reach the excluded fields (the global filters themselves), answer for the system and cross everything.
Complex filtering¶
# Nested AND/OR
GET /api/products/
X-Filter: ["&", [
["is_active", "is true"],
["|", [["price", "<", 50], ["category.slug", "=", "sale"]]]
]]
Error responses¶
- 422: Invalid field, operator, or JSON format
- 422: A path crossing more relations than
filter_max_depth - 422: Type conversion errors
Programmatic usage¶
For advanced use cases where you need to build filters programmatically in Python code, check out the advanced guide.