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 build in exact
& iExact
lookups cannot be used to filter for None
and isNull
have to be used explicitly.
value resolution¶
value
parameter of typerelay.GlobalID
is resolved to itsnode_id
attributevalue
parameter of typeEnum
is resolved to is's value- above types are converted in
lists
as 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
name
ends up filteringFruit
instead ofColor
without applyingprefix
value
- represents graphql field type- Required, but forbidden for default
filter
method - must be annotated
- used instead of field's return type
queryset
- can be used for more complex filtering- Optional, but Required for default
filter
method - usually used to
annotate
QuerySet
Resolver return¶
For custom field methods two return values are supported
- django's
Q
object - tuple with
QuerySet
and django'sQ
object ->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
queryset
is Required - argument
value
is 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
&bool
fields
RangeLookup
¶
- used for
range
orBETWEEN
filtering
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
filter
methods - disable USE_DEPRECATED_FILTERS - This is breaking change