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
inputFruitFilter {
id: ID
name: String
AND: FruitFilter
OR: FruitFilter
NOT: FruitFilter
DISTINCT: Boolean
}
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
{
fruits(
filters: {
name: "kebab"
OR: {
name: "raspberry"
}
}
) { ... }
}
List-based AND/OR/NOT Filters
The AND , OR , and NOT operators can also be declared as lists, allowing for more complex combinations of conditions. This is particularly useful when you need to combine multiple conditions in a single operation.
The code above would generate the following schema:
schema.graphql
inputIDBaseFilterLookup {
exact: ID
isNull: Boolean
inList: [String!]
}
inputStrFilterLookup {
exact: ID
isNull: Boolean
inList: [String!]
iExact: String
contains: String
iContains: String
startsWith: String
iStartsWith: String
endsWith: String
iEndsWith: String
regex: String
iRegex: String
}
inputFruitFilter {
id: IDFilterLookup
name: StrFilterLookup
AND: FruitFilter
OR: FruitFilter
NOT: FruitFilter
DISTINCT: Boolean
}
Single-field lookup can be annotated with the appropriate lookup type for the field.
Use specific lookup types like StrFilterLookup for strings, ComparisonFilterLookup for numbers, etc.
types.py
from strawberry_django import StrFilterLookup
@strawberry_django.filter_type(models.Fruit)
classFruitFilter:
name: StrFilterLookup | None
Warning
Avoid using FilterLookup[str] directly. Use the specific lookup type (StrFilterLookup )
instead to prevent DuplicatedTypeName errors. See the Generic Lookup reference
for the full list of available lookup types.
Filtering over relationships
types.py
@strawberry_django.filter_type(models.Color)
classColorFilter:
id: auto
name: auto
@strawberry_django.filter_type(models.Fruit)
classFruitFilter:
id: auto
name: auto
color: ColorFilter | None
The code above would generate following schema:
schema.graphql
inputColorFilter {
id: ID
name: String
AND: ColorFilter
OR: ColorFilter
NOT: ColorFilter
}
inputFruitFilter {
id: ID
name: String
color: ColorFilter
AND: FruitFilter
OR: FruitFilter
NOT: FruitFilter
}
Custom filter methods
You can define custom filter method by defining your own resolver.
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
value parameter of type relay.GlobalID is resolved to its node_id attribute
value parameter of type Enum is resolved to isโs value
value parameter wrapped in strawberry.Some (from Maybe type) is unwrapped and resolved
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
Virtual (non-filtering) fields
Sometimes you need a field on the filter input that is not a database filter itself, but a
parameter consumed by a custom filter method (e.g. a similarity threshold, a search mode flag).
Use strawberry_django.filter_field(skip_queryset_filter=True) to declare such fields. They appear in
the GraphQL schema but are skipped during filter processing. Access them via self.<field> in
your custom filter method.
As seen above strawberry_django.process_filters function is exposed and can be
reused in custom methods.
For filter method filterskip_object_filter_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:
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