Filtering¶
It is possible to define filters for Django types, which will be converted into .filter(...) queries for the ORM:
| types.py | |
|---|---|
Tip
In most cases filter fields should have Optional annotations and default value strawberry.UNSET like so: foo: Optional[SomeType] = strawberry.UNSET Above auto annotation is wrapped in Optional automatically. UNSET is automatically used for fields without field or with strawberry_django.filter_field.
The code above would generate following schema:
| schema.graphql | |
|---|---|
Tip
If you are using the relay integration and working with types inheriting from relay.Node and GlobalID for identifying objects, you might want to set MAP_AUTO_ID_AS_GLOBAL_ID=True in your strawberry django settings to make sure auto fields gets mapped to GlobalID on types and filters.
AND, OR, NOT, DISTINCT ...¶
To every filter AND, OR, NOT & DISTINCT fields are added to allow more complex filtering
Lookups¶
Lookups can be added to all fields with lookups=True, which will add more options to resolve each type. For example:
| types.py | |
|---|---|
The code above would generate the following schema:
Single-field lookup can be annotated with the FilterLookup generic type.
| types.py | |
|---|---|
Filtering over relationships¶
| types.py | |
|---|---|
The code above would generate following schema:
| schema.graphql | |
|---|---|
Custom filter methods¶
You can define custom filter method by defining your own resolver.
Warning
It is discouraged to use queryset.filter() directly. When using more complex filtering via NOT, OR & AND this might lead to undesired behaviour.
Tip
process_filters¶
As seen above strawberry_django.process_filters function is exposed and can be reused in custom methods. Above it's used to resolve fields lookups
null values¶
By default null value is ignored for all filters & lookups. This applies to custom filter methods as well. Those won't even be called (you don't have to check for None). This can be modified using strawberry_django.filter_field(filter_none=True)
This also means that built in exact & iExact lookups cannot be used to filter for None and isNull have to be used explicitly.
value resolution¶
valueparameter of typerelay.GlobalIDis resolved to itsnode_idattributevalueparameter of typeEnumis resolved to is's value- above types are converted in
listsas well
resolution can modified via strawberry_django.filter_field(resolve_value=...)
- True - always resolve
- False - never resolve
- UNSET (default) - resolves for filters without custom method only
The code above generates the following schema:
| schema.graphql | |
|---|---|
Resolver arguments¶
prefix- represents the current path or position- Required
- Important for nested filtering
- In code bellow custom filter
nameends up filteringFruitinstead ofColorwithout applyingprefix
value- represents graphql field type- Required, but forbidden for default
filtermethod - must be annotated
- used instead of field's return type
queryset- can be used for more complex filtering- Optional, but Required for default
filtermethod - usually used to
annotateQuerySet
Resolver return¶
For custom field methods two return values are supported
- django's
Qobject - tuple with
QuerySetand django'sQobject ->tuple[QuerySet, Q]
For default filter method only second variant is supported.
What about nulls?¶
By default null values are ignored. This can be toggled as such @strawberry_django.filter_field(filter_none=True)
Overriding the default filter method¶
Works similar to field filter method, but:
- is responsible for resolution of filtering for entire object
- must be named
filter - argument
querysetis Required - argument
valueis Forbidden
Tip
As seen above strawberry_django.process_filters function is exposed and can be reused in custom methods. For filter method filter skip_object_order_method was used to avoid endless recursion.
Adding filters to types¶
All fields and CUD mutations inherit filters from the underlying type by default. So, if you have a field like this:
| types.py | |
|---|---|
The fruits field will inherit the filters of the type in the same way as if it was passed to the field.
Adding filters directly into a field¶
Filters added into a field override the default filters of this type.
| schema.py | |
|---|---|
Generic Lookup reference¶
There is 7 already defined Generic Lookup strawberry.input classes importable from strawberry_django
BaseFilterLookup¶
- contains
exact,isNull&inList - used for
ID&boolfields
RangeLookup¶
- used for
rangeorBETWEENfiltering
ComparisonFilterLookup¶
- inherits
BaseFilterLookup - additionaly contains
gt,gte,lt,lte, &range - used for Numberical fields
FilterLookup¶
- inherits
BaseFilterLookup - additionally contains
iExact,contains,iContains,startsWith,iStartsWith,endsWith,iEndsWith,regex&iRegex - used for string based fields and as default
DateFilterLookup¶
- inherits
ComparisonFilterLookup - additionally contains
year,month,day,weekDay,isoWeekDay,week,isoYear&quarter - used for date based fields
TimeFilterLookup¶
- inherits
ComparisonFilterLookup - additionally contains
hour,minute,second,date&time - used for time based fields
DatetimeFilterLookup¶
- inherits
DateFilterLookup&TimeFilterLookup - used for timedate based fields
Legacy filtering¶
The previous version of filters can be enabled via USE_DEPRECATED_FILTERS
Warning
If USE_DEPRECATED_FILTERS is not set to True legacy custom filtering methods will be not be called.
When using legacy filters it is important to use legacy strawberry_django.filters.FilterLookup lookups as well. The correct version is applied for auto annotated filter field (given lookups=True being set). Mixing old and new lookups might lead to error DuplicatedTypeName: Type StrFilterLookup is defined multiple times in the schema.
While legacy filtering is enabled new filtering custom methods are fully functional including default filter method.
Migration process could be composed of these steps:
- enable USE_DEPRECATED_FILTERS
- gradually transform custom filter field methods to new version (do not forget to use old FilterLookup if applicable)
- gradually transform default
filtermethods - disable USE_DEPRECATED_FILTERS - This is breaking change