Filtering and sorting data
You can filter data using the following methods (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]] -
query set proxy
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 sort the data using the following method (sql order by clause).
order_by(columns:Union[List, str, OrderAction]) -> QuerySet- query set proxy
QuerysetProxy.order_by(columns:Union[List, str, OrderAction])method
filtration
screen
filter(*args, **kwargs) -> QuerySet
Allows you to filter by any model attribute/field and get instances using filters across FK relationships.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Django-style filters
You can change the filter operand using special filter suffixes:
- exact-matches exactly with value, sql column =
* can be written as album__name__exact='Malibu' - iexact -exact match sql column =
(case insensitive) - can be written as album__name__iexact='malibu'
- contains- sql column LIKE '%
%'* can be written as album__name__contains ='Mal' - icontains - sql column LIKE '%
%'(case insensitive)* can be written as album__name__icontains='mal' - in-sql
column IN (<VALUE1>, <VALUE2>, ...)* can be writtenalbum__name__in=['Malibu', 'Barclay'] - isnull - sql column IS NULL (and sql column IS NOT NULL)
- can be written as album__name__isnull=True (isnotnull album__name__isnull=False)
- gt - sql column>
(greater than)* can be written as position__gt=3 - gte - sql column>=
(greater than or equal to)* can be written as position__gte=3 - lt - sql column <
(below)* can be written as position__lt=3 - lte - sql column <=
(less than or equal to)* can be written as position__lte=3 - startswith - sql column LIKE '
%'* can be written as album__name__startswith='Mal' - istartswith - sql column LIKE '
%'(case insensitive)* can be written as album__name__istartswith='mal' - endswith - sql column LIKE '%
'* can be written as album__name__endswith='ibu' - iendswith - sql column LIKE '%
'(case-insensitive)* can be written as album__name__iendswith='IBU'
Some samples:
1 2 3 4 5 6 7 8 9 10 11 | |
Python-style filters
- Exact-exactly matches the value, sql column =
- It can be written as www.example.com =='Malibu
- iexact-exact match sql column =
(case insensitive) - can be written as
Track.album.name.iexact('malibu')
- can be written as
- CONTAINS- sql COLUMN LIKE '%
%' * It can be written as Track.album.name % 'Mal') * can be written as Track.album.name.contains('Mal') - icontains-sql column LIKE ' %
%'(case insensitive)* can be written as Track.album.name.icontains('mal') - in-sql
column IN (<VALUE1>, <VALUE2>, ...)*can be writtenTrack.album.name << ['Malibu', 'Barclay']*can be writtenTrack.album.name.in_(['Malibu', 'Barclay']) - isnull - sql column IS NULL (and sql column IS NOT NULL)* You can write Track.album.name>> None * Can be written as Track.album.name.isnull(True) * It can be written as not null.
Track.album.name.isnull(False)* not null can be written ~(Track.album.name >> None) * not null can be written~(Track.album.name.isnull(True)) - gt-sql column>
(greater than)* can be written as www.example.com> 3 - gte-sql column>=
(greater than or equal to)* can be written as www.example.com>= 3 - lt-sql column <
(below)* can be written as www.example.com <3 - lte-sql column <=
(less than or equal to)* can be written as www.example.com <= 3 - startswith-sql column LIKE '
%'* can be written as Track.album.name.startswith('Mal') - istartswith - sql column LIKE '
%'(case insensitive)* can be written as Track.album.name.istartswith('mal') - endswith - sql column LIKE '%
'* can be written as Track.album.name.endswith('ibu') - iendswith - sql column LIKE '%
'(case insensitive)* can be written as Track.album.name.iendswith('IBU')
Some samples:
1 2 3 4 5 6 7 8 9 10 11 | |
Note
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 is added for you. If you include % in the search value, it will be escaped and treated as a literal percent sign within the text.
exclude
exclude(*args, **kwargs) -> QuerySet
Works exactly the same as filters, and all modifiers (suffixes) are the same, but returns the not condition.
So if you use filter(name ='John '), which equals where name ='John' in SQL, then except(name ='John ') equals where name <> 'John'
Note that all conditions are joined, so if you pass multiple values, it becomes the union of the conditions.
Excluding (name ='John ',age>=35) becomes where not (name='John' and age>=35)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Complex filters (including OR)
By default, both filter() and except() methods combine the filter options provided with AND conditions so that filter(name="John", age__gt=30) translates to WHERE name = 'John' AND age > 30.
Sometimes it's useful to query a database with conditions that shouldn't be federated, such as WHERE name = 'John' OR age > 30, or to build a complex where query over which you want more control. After all,WHERE (name = 'John' OR age > 30) and city='New York' is completely different from WHERE name = 'John' OR (age > 30 and city='New York').
To construct OR and nested conditions, ormar provides two functions that can be used in filter() and except() in QuerySet and QuerysetProxy.
!!!Note that you can provide these methods in any other method that accepts*args, such as get() or all().
Calls to or_and and_can be nested within each other or combined with keyword arguments. Since it sounds more complicated than it is, let's look at some examples.
Given an example model 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 example complex queries:
Let's choose Tolkien's books 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 | |
Let us now choose books written by Tolkien after 1960 or before 1940.
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 | |
Sapkovsky books before 2000 or Tolkien books 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, these functions can have more than two conditions, so if we want books that contain "hobbits":
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 conditions deeper as needed, for example by implementing the following query:
sql:
1 2 3 | |
You can structure queries 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 | |
You should now understand how ormar.or_and ormar.and_work. Of course, you can link them to any other method of query set, so in the example, a fully valid query might look like this:
1 2 3 4 5 6 7 8 9 10 11 | |
The same applies to python-style linking and nesting.
Django style
Note that with django style, you cannot supply the same keyword argument multiple times, so the query filter(ormar.or_(name='Jack', name='John')) below is not allowed. If you want to check multiple values of the same column, just use the in operator:filter(name__in=['Jack','John']).
If you pass only one argument to the or_or and_function, it is only enclosed in parentheses and has no effect on the actual query, so all three queries end up being the same:
1 2 3 | |
!!!note Note or_and_queries will have WHERE (title ='The Hobbit') but the brackets are redundant and have no practical effect.
If you really need to use the same field name twice, you can use this feature. Remember that you cannot pass the same keyword argument to a function twice, so how do you query WHERE (authors.name LIKE '%tolkien%') OR (authors.name LIKE '%sapkowski%')) in the example?
You can't do this:
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 use the same field as many times as you want.
1 2 3 4 5 6 7 8 | |
get
get(*args, **kwargs) -> Model
Get the first row from the database that satisfies the kwargs setting criteria.
When passing any args and/or kwargs, it is the equivalent of a shortcut to calling filter(*args, **kwargs).get()
!!!tip To learn more about filters, go to Filters.
1 | |
Get or None
Exactly the same as get described above, but returns None if no database record matching the condition is found instead of throwing an exception.
acquiring or creating
get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs) -> Tuple[Model, bool]
A combination of create and get methods.
When passing any args and/or kwargs, it is the shortcut equivalent to calling filter(*args, **kwargs).get_or_create()
!!!tip To learn more about filters, go to Filters.
1 | |
!!!warning When a given item does not exist, you need to pass kwargs for all required fields of the model, including but not limited to the Primary_key column (unless it is autoincrement).
all
all(*args, **kwargs) -> List[Optional["Model"]]
For filter options set, returns all rows in the database for a given model.
When passing any kwargs, it is the equivalent of a shortcut to calling filter(*args, **kwargs).all()
!!!tip To learn more about filters, go to Filters.
1 | |
QuerysetProxy method
Returns a list of related models when directly accessing the related ManyToMany field and ReverseForeignKey.
But at the same time it exposes a subset of the QuerySet API, so you can filter, create, select related models, etc. directly from the parent model.
screen
Same filtering functionality as above, but allows you to filter related objects from the other end of the relationship.
!!!tip To learn more about QuerysetProxy, visit the QuerysetProxy section
exclude
Exactly the same exclusion functionality as above, but allows you to filter related objects from the other side of the relationship.
!!!tip To learn more about QuerysetProxy, visit the QuerysetProxy section
get
Exactly the same as the get function above, but allows you to filter related objects from the other end of the relationship.
!!!tip To learn more about QuerysetProxy, visit the QuerysetProxy section
Get or None
Exactly the same as get described above, but returns None if no database record matching the condition is found instead of throwing an exception.
acquiring or creating
Identical to the get_or_create function above, but allows you to filter related objects from the other end of the relationship.
!!!tip To learn more about QuerysetProxy, visit the QuerysetProxy section
all
All the same functionality as above, but allows you to filter related objects from the other side of the relationship.
!!!tip To learn more about QuerysetProxy, visit the QuerysetProxy section
sort
Order Basis
order_by(columns: Union[List, str, OrderAction]) -> QuerySet
Using order_by(), you can sort the results in the database based on the fields you select.
You can provide strings with field names or lists of strings with different fields.
Sorts in sql are applied in the order of the names you provide in order_by.
!!!tip By default, if you do not provide sorting or explicitly sort by all primary keys
!!!Warning If you sort by nested models, result rows will not be sorted by main model, otherwise mar will merge these child rows into one main model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Given an example model:
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 sort by main model field, simply provide the field name
Django style
1 2 3 4 5 6 | |
Python style
1 2 3 4 5 6 | |
To sort nested models, use dunder '__' to separate field names.
This way you can sort all relationship 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 before the field name
Django style
1 2 3 4 5 6 7 8 | |
Python style
1 2 3 4 5 6 7 8 | |
Note
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 there is no guarantee of the order of rows in the database, ormar always issues an order by sql clause to each (partial) query, even if you do not supply the order yourself.
By default, when querying a database with a given model, the models are sorted in ascending order by the Primary_key column. If you want to change the default behavior, you can do so by supplying the orders_by parameter to ormar_config.
!!! Tip To learn more about model sort order, visit the Models section of the document
By default, relationships follow the same order, but you can modify the order in which related models are loaded during a query by supplying the orders_by and related_orders_by parameters to the relationship.
!!! Tip To read more about model sort order, visit the relationships section of the document
The order in which the order_by clause is applied is as follows:
- Explicitly passing the order_by() call in the query
- Relationships through orders_by and related_orders_by (if any)
- ormar_config object orders_by for model
- The model's primary_key column is in ascending order (backup, used if none of the above is provided)
Apply orders from only one source to each model (so that you can always override it in a single query).
This means that if you provide an explicit order_by for the model in the query, relationships and model sort order are skipped.
If you provide relationship one, model sorting is skipped.
Finally, if you provide one for the Model, the default value for primary_key is skipped.
QuerysetProxy method
Returns a list of related models when directly accessing the related ManyToMany field and ReverseForeignKey.
But it also exposes a subset of the QuerySet API, so you can filter, create, select related models, and so on directly from the parent model.
Order Basis
Exactly the same as the order_by function above, but allows you to sort related objects from the other side of the relationship.
!!!tip To learn more about QuerysetProxy, visit the QuerysetProxy section