Filtering and sorting data
You can use following methods to filter the data (sql where clause).
filter(*args, **kwargs) -> QuerySet
exclude(*args, **kwargs) -> QuerySet
get(*args, **kwargs) -> Model
get_or_none(*args, **kwargs) -> Optional[Model]
get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs) -> Tuple[Model, bool]
-
all(*args, **kwargs) -> List[Optional[Model]]
-
QuerysetProxy
QuerysetProxy.filter(*args, **kwargs)
methodQuerysetProxy.exclude(*args, **kwargs)
methodQuerysetProxy.get(*args, **kwargs)
methodQuerysetProxy.get_or_none(*args, **kwargs)
methodQuerysetProxy.get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs)
methodQuerysetProxy.all(*args, **kwargs)
method
And following methods to sort the data (sql order by clause).
order_by(columns:Union[List, str, OrderAction]) -> QuerySet
QuerysetProxy
QuerysetProxy.order_by(columns:Union[List, str, OrderAction])
method
Filtering
filter
filter(*args, **kwargs) -> QuerySet
Allows you to filter by any Model
attribute/field as well as to fetch instances, with
a filter across an FK relationship.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 |
|
Django style filters
You can use special filter suffix to change the filter operands:
- exact - exact match to value, sql
column = <VALUE>
- can be written as
album__name__exact='Malibu'
- can be written as
- iexact - exact match sql
column = <VALUE>
(case insensitive)- can be written as
album__name__iexact='malibu'
- can be written as
- contains - sql
column LIKE '%<VALUE>%'
- can be written as
album__name__contains='Mal'
- can be written as
- icontains - sql
column LIKE '%<VALUE>%'
(case insensitive)- can be written as
album__name__icontains='mal'
- can be written as
- in - sql
column IN (<VALUE1>, <VALUE2>, ...)
- can be written as
album__name__in=['Malibu', 'Barclay']
- can be written as
- isnull - sql
column IS NULL
(and sqlcolumn IS NOT NULL
)- can be written as
album__name__isnull=True
(isnotnullalbum__name__isnull=False
)
- can be written as
- gt - sql
column > <VALUE>
(greater than)- can be written as
position__gt=3
- can be written as
- gte - sql
column >= <VALUE>
(greater or equal than)- can be written as
position__gte=3
- can be written as
- lt - sql
column < <VALUE>
(lower than)- can be written as
position__lt=3
- can be written as
- lte - sql
column <= <VALUE>
(lower equal than)- can be written as
position__lte=3
- can be written as
- startswith - sql
column LIKE '<VALUE>%'
(exact start match)- can be written as
album__name__startswith='Mal'
- can be written as
- istartswith - sql
column LIKE '<VALUE>%'
(case insensitive)- can be written as
album__name__istartswith='mal'
- can be written as
- endswith - sql
column LIKE '%<VALUE>'
(exact end match)- can be written as
album__name__endswith='ibu'
- can be written as
- iendswith - sql
column LIKE '%<VALUE>'
(case insensitive)- can be written as
album__name__iendswith='IBU'
- can be written as
Some samples:
1 2 3 4 5 6 7 8 9 10 11 |
|
Python style filters
- exact - exact match to value, sql
column = <VALUE>
- can be written as
Track.album.name == 'Malibu
- can be written as
- iexact - exact match sql
column = <VALUE>
(case insensitive)- can be written as
Track.album.name.iexact('malibu')
- can be written as
- contains - sql
column LIKE '%<VALUE>%'
- can be written as
Track.album.name % 'Mal')
- can be written as
Track.album.name.contains('Mal')
- can be written as
- icontains - sql
column LIKE '%<VALUE>%'
(case insensitive)- can be written as
Track.album.name.icontains('mal')
- can be written as
- in - sql
column IN (<VALUE1>, <VALUE2>, ...)
- can be written as
Track.album.name << ['Malibu', 'Barclay']
- can be written as
Track.album.name.in_(['Malibu', 'Barclay'])
- can be written as
- isnull - sql
column IS NULL
(and sqlcolumn IS NOT NULL
)- can be written as
Track.album.name >> None
- can be written as
Track.album.name.isnull(True)
- not null can be written as
Track.album.name.isnull(False)
- not null can be written as
~(Track.album.name >> None)
- not null can be written as
~(Track.album.name.isnull(True))
- can be written as
- gt - sql
column > <VALUE>
(greater than)- can be written as
Track.album.name > 3
- can be written as
- gte - sql
column >= <VALUE>
(greater or equal than)- can be written as
Track.album.name >= 3
- can be written as
- lt - sql
column < <VALUE>
(lower than)- can be written as
Track.album.name < 3
- can be written as
- lte - sql
column <= <VALUE>
(lower equal than)- can be written as
Track.album.name <= 3
- can be written as
- startswith - sql
column LIKE '<VALUE>%'
(exact start match)- can be written as
Track.album.name.startswith('Mal')
- can be written as
- istartswith - sql
column LIKE '<VALUE>%'
(case insensitive)- can be written as
Track.album.name.istartswith('mal')
- can be written as
- endswith - sql
column LIKE '%<VALUE>'
(exact end match)- can be written as
Track.album.name.endswith('ibu')
- can be written as
- iendswith - sql
column LIKE '%<VALUE>'
(case insensitive)- can be written as
Track.album.name.iendswith('IBU')
- can be written as
Some samples:
1 2 3 4 5 6 7 8 9 10 11 |
|
Note
All methods that do not return the rows explicitly returns a QuerySet instance so you can chain them together
So operations like filter()
, select_related()
, limit()
and offset()
etc. can be chained.
Something like Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()
Warning
Note that you do not have to specify the %
wildcard in contains and other
filters, it's added for you. If you include %
in your search value it will be escaped
and treated as literal percentage sign inside the text.
exclude
exclude(*args, **kwargs) -> QuerySet
Works exactly the same as filter and all modifiers (suffixes) are the same, but returns a not condition.
So if you use filter(name='John')
which equals to where name = 'John'
in SQL,
the exclude(name='John')
equals to where name <> 'John'
Note that all conditions are joined so if you pass multiple values it becomes a union of conditions.
exclude(name='John', age>=35)
will become where not (name='John' and age>=35)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 |
|
Complex filters (including OR)
By default both filter()
and exclude()
methods combine provided filter options with
AND
condition so filter(name="John", age__gt=30)
translates into WHERE name = 'John' AND age > 30
.
Sometimes it's useful to query the database with conditions that should not be applied
jointly like WHERE name = 'John' OR age > 30
, or build a complex where query that you would
like to have bigger control over. After all WHERE (name = 'John' OR age > 30) and city='New York'
is
completely different than WHERE name = 'John' OR (age > 30 and city='New York')
.
In order to build OR
and nested conditions ormar provides two functions that can be used in
filter()
and exclude()
in QuerySet
and QuerysetProxy
.
Note
Note that you can provide those methods in any other method like get()
or all()
that accepts *args
.
Call to or_
and and_
can be nested in each other, as well as combined with keyword arguments.
Since it sounds more complicated than it is, let's look at some examples.
Given a sample models like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Let's create some sample data:
1 2 3 4 5 6 7 |
|
We can construct some sample complex queries:
Let's select books of Tolkien OR books written after 1970
sql:
WHERE ( authors.name = 'J.R.R. Tolkien' OR books.year > 1970 )
Django style
1 2 3 4 5 6 |
|
Python style
1 2 3 4 5 6 |
|
Now let's select books written after 1960 or before 1940 which were written by Tolkien.
sql:
WHERE ( books.year > 1960 OR books.year < 1940 ) AND authors.name = 'J.R.R. Tolkien'
Django style
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Python style
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Books of Sapkowski from before 2000 or books of Tolkien written after 1960
sql:
WHERE ( ( books.year > 1960 AND authors.name = 'J.R.R. Tolkien' ) OR ( books.year < 2000 AND authors.name = 'Andrzej Sapkowski' ) )
Django style
1 2 3 4 5 6 7 8 9 10 11 |
|
Python style
1 2 3 4 5 6 7 8 9 |
|
Of course those functions can have more than 2 conditions, so if we for example want books that contains 'hobbit':
sql:
WHERE ( ( books.year > 1960 AND authors.name = 'J.R.R. Tolkien' ) OR
( books.year < 2000 AND os0cec_authors.name = 'Andrzej Sapkowski' ) OR
books.title LIKE '%hobbit%' )
Django style
1 2 3 4 5 6 7 8 9 10 11 |
|
Python style
1 2 3 4 5 6 7 8 9 |
|
If you want or need to you can nest deeper conditions as deep as you want, in example to achieve a query like this:
sql:
1 2 3 |
|
You can construct a query as follows:
Django style
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Python style
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
By now you should already have an idea how ormar.or_
and ormar.and_
works.
Of course, you could chain them in any other methods of queryset, so in example a perfectly
valid query can look like follows:
1 2 3 4 5 6 7 8 9 10 11 |
|
Same applies to python style chaining and nesting.
Django style
Note that with django style you cannot provide the same keyword argument several times so queries like filter(ormar.or_(name='Jack', name='John'))
are not allowed. If you want to check the same
column for several values simply use in
operator: filter(name__in=['Jack','John'])
.
If you pass only one parameter to or_
or and_
functions it's simply wrapped in parenthesis and
has no effect on actual query, so in the end all 3 queries are identical:
1 2 3 |
|
Note
Note that or_
and and_
queries will have WHERE (title='The Hobbit')
but the parenthesis is redundant and has no real effect.
This feature can be used if you really need to use the same field name twice.
Remember that you cannot pass the same keyword arguments twice to the function, so
how you can query in example WHERE (authors.name LIKE '%tolkien%') OR (authors.name LIKE '%sapkowski%'))
?
You cannot do:
1 2 3 4 5 6 7 8 |
|
But you can do this:
1 2 3 4 5 6 7 8 9 |
|
Python style
Note that with python style you can perfectly use the same fields as many times as you want.
1 2 3 4 5 6 7 8 |
|
get
get(*args, **kwargs) -> Model
Gets the first row from the db meeting the criteria set by kwargs.
When any args and/or kwargs are passed it's a shortcut equivalent to calling filter(*args, **kwargs).get()
get_or_none
Exact equivalent of get described above but instead of raising the exception returns None
if no db record matching the criteria is found.
get_or_create
get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs) -> Tuple[Model, bool]
Combination of create and get methods.
When any args and/or kwargs are passed it's a shortcut equivalent to calling filter(*args, **kwargs).get_or_create()
Tip
To read more about filter
go to filter.
To read more about get_or_create
go to read/get_or_create
Warning
When given item does not exist you need to pass kwargs for all required fields of the model, including but not limited to primary_key column (unless it's autoincrement).
all
all(*args, **kwargs) -> List[Optional["Model"]]
Returns all rows from a database for given model for set filter options.
When any kwargs are passed it's a shortcut equivalent to calling filter(*args, **kwargs).all()
QuerysetProxy methods
When access directly the related ManyToMany
field as well as ReverseForeignKey
returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create, select related etc related models directly from parent model.
filter
Works exactly the same as filter function above but allows you to filter related objects from other side of the relation.
Tip
To read more about QuerysetProxy
visit querysetproxy section
exclude
Works exactly the same as exclude function above but allows you to filter related objects from other side of the relation.
Tip
To read more about QuerysetProxy
visit querysetproxy section
get
Works exactly the same as get function above but allows you to filter related objects from other side of the relation.
Tip
To read more about QuerysetProxy
visit querysetproxy section
get_or_none
Exact equivalent of get described above but instead of raising the exception returns None
if no db record matching the criteria is found.
get_or_create
Works exactly the same as get_or_create function above but allows you to filter related objects from other side of the relation.
Tip
To read more about QuerysetProxy
visit querysetproxy section
all
Works exactly the same as all function above but allows you to filter related objects from other side of the relation.
Tip
To read more about QuerysetProxy
visit querysetproxy section
Sorting
order_by
order_by(columns: Union[List, str, OrderAction]) -> QuerySet
With order_by()
you can order the results from database based on your choice of
fields.
You can provide a string with field name or list of strings with different fields.
Ordering in sql will be applied in order of names you provide in order_by.
Tip
By default if you do not provide ordering ormar
explicitly orders by all
primary keys
Warning
If you are sorting by nested models that causes that the result rows are
unsorted by the main model
ormar
will combine those children rows into one main model.
Sample raw database rows result (sort by child model desc):
1 2 3 |
|
will result in 2 rows of result:
1 2 |
|
The main model will never duplicate in the result
Given sample Models like following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
To order by main model field just provide a field name
Django style
1 2 3 4 5 6 |
|
Python style
1 2 3 4 5 6 |
|
To sort on nested models separate field names with dunder '__'.
You can sort this way across all relation types -> ForeignKey
, reverse virtual FK
and ManyToMany
fields.
Django style
1 2 3 4 |
|
Python style
1 2 3 4 |
|
To sort in descending order provide a hyphen in front of the field name
Django style
1 2 3 4 5 6 7 8 |
|
Python style
1 2 3 4 5 6 7 8 |
|
Note
All methods that do not return the rows explicitly returns a QuerySet instance so you can chain them together
So operations like filter()
, select_related()
, limit()
and offset()
etc. can be chained.
Something like Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()
Default sorting in ormar
Since order of rows in a database is not guaranteed, ormar
always issues an order by
sql clause to each (part of) query even if you do not provide order yourself.
When querying the database with given model by default the Model
is ordered by the primary_key
column ascending. If you wish to change the default behaviour you can do it by providing orders_by
parameter to ormar_config
.
Tip
To read more about models sort order visit models section of documentation
By default the relations follow the same ordering, but you can modify the order in which related models are loaded during query by providing orders_by
and related_orders_by
parameters to relations.
Tip
To read more about models sort order visit relations section of documentation
Order in which order_by clauses are applied is as follows:
- Explicitly passed
order_by()
calls in query - Relation passed
orders_by
andrelated_orders_by
if exists - Model's
ormar_config
objectorders_by
- Model's
primary_key
column ascending (fallback, used if none of above provided)
Order from only one source is applied to each Model
(so that you can always overwrite it in a single query).
That means that if you provide explicit order_by
for a model in a query, the Relation
and Model
sort orders are skipped.
If you provide a Relation
one, the Model
sort is skipped.
Finally, if you provide one for Model
the default one by primary_key
is skipped.
QuerysetProxy methods
When access directly the related ManyToMany
field as well as ReverseForeignKey
returns the list of related models.
But at the same time it exposes subset of QuerySet API, so you can filter, create, select related etc related models directly from parent model.
order_by
Works exactly the same as order_by function above but allows you to sort related objects from other side of the relation.
Tip
To read more about QuerysetProxy
visit querysetproxy section