Filtering๐
In this section, we'll cover the everything necessary for filtering
results returned by your QueryTypes.
FilterSet๐
A FilterSet is a collection of Filter objects that represents
an InputObjectType in the GraphQL schema. When added to a QueryType,
it creates an input argument (as determined by the
QUERY_TYPE_FILTER_INPUT_KEY setting)
on any list Entrypoint or many-related Field that is created using that QueryType.
That input can then be used to filter the results returned by the Entrypoint or Field.
A basic FilterSet is created by subclassing FilterSet
and adding a Django Model to it as a generic type parameter.
You must also add at least one Filter to the class body of the FilterSet.
Then the FilterSet can be added to a QueryType using the filterset argument.
You can also add the FilterSet to the QueryType using decorator syntax.
Auto-generation๐
A FilterSet can automatically introspect its Django Model and convert the Model's fields
to Filters on the FilterSet. For example, if the Task model has the following fields:
An auto-generated FilterSet will have all of the Task Model's fields and those fields'
lookups translated into input arguments.
Here is the generated InputObjectType
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
About Filter names
Usually the names of the Filters generated by auto-generation correspond to the lookup
in Django, but for text-based fields, names are changed slightly to lean towards using
case-insensitive lookups first: Filter name uses __iexact and nameExact uses __exact.
Similarly, nameStartsWith uses __istartswith while nameStartsWithExact uses __startswith, etc.
To use auto-generation, either set AUTOGENERATION setting to True
to enable it globally, or set the auto argument to True in the FilterSet class definition.
With this, you can leave the FilterSet class body empty.
You can exclude some Model fields from the auto-generation by setting the exclude argument:
You can also exclude specific model lookups, e.g. created_at__gte.
Logical operators๐
A FilterSet always provides the logical operators NOT, AND, OR, XOR,
allowing users to freely create more complex filter conditions from defined Filters.
Let's assume you've added an auto-generated TaskFilterSet
for a QueryType named TaskType. Normally, when multiple Filters are used,
you'll get results that match all filter conditions.
By putting the filter conditions inside an OR block,
we can get results that match any of the conditions.
Note that only the results inside the conditional block will use that logical combinator. For example, in the following example, only tasks that contains an "e" AND EITHER start with "a" OR are done will be returned:
Filter queryset๐
In addition to Filters, FilterSet also includes a __filter_queryset__
classmethod, which can be used to add filtering that should always be applied
when fetching objects through QueryTypes using the given FilterSet.
Note that QueryTypes also have a __filter_queryset__ classmethod, which is run before
any FilterSet Filters, and that FilterSet's __filter_queryset__ is run after.
See the Optimizer's order of operations for more details.
Schema name๐
By default, the name of the generated GraphQL InputObjectType for a FilterSet class
is the name of the FilterSet class. If you want to change the name separately,
you can do so by setting the schema_name argument:
Description๐
You can provide a description for a FilterSet by adding a docstring to the class.
Directives๐
You can add directives to a FilterSet by providing them using the directives argument.
The directive must be usable in the INPUT_OBJECT location.
You can also add directives using decorator syntax.
See the Directives section for more details on directives.
Visibility๐
This is an experimental feature that needs to be enabled using the
EXPERIMENTAL_VISIBILITY_CHECKSsetting.
You can hide a FilterSet from certain users by using the __is_visible__ method.
Hiding the FilterSet means that it will not be included in introspection queries for that user,
and trying to use it in operations will result in an error that looks exactly like
the argument for the FilterSet didn't exist in the first place.
When using visibility checks, you should also disable "did you mean" suggestions using the
ALLOW_DID_YOU_MEAN_SUGGESTIONSsetting. Otherwise, a hidden field might show up in them.
GraphQL extensions๐
You can provide custom extensions for the FilterSet by providing a
extensions argument with a dictionary containing them. These can then be used
however you wish to extend the functionality of the FilterSet.
FilterSet extensions are made available in the GraphQL InputObjectType extensions
after the schema is created. The FilterSet itself is found in the GraphQL InputObjectType extensions
under a key defined by the FILTERSET_EXTENSIONS_KEY
setting.
Filter๐
A Filter defines a way of filtering the results returned by an Entrypoint or Field using a QueryType.
A Filter corresponds to anything that can be passed to a queryset.filter() call,
usually a lookup expression on the Django Model of the FilterSet it belongs to.
In GraphQL, a Filter represents a GraphQLInputField on an InputObjectType.
A Filter always requires a reference from which it will create the proper GraphQL resolver
and input type for the Filter.
Model field references๐
For Filters corresponding to Django Model fields, the Filter can be used without passing in a reference,
as its attribute name on the FilterSet class body can be used to identify
the corresponding Model field.
To be a bit more explicit, you could use a string referencing the Model field:
For better type safety, you can also use the Model field itself:
Being explicit like this is only required if the name of the attribute in the GraphQL schema is different from the Model field name.
Expression references๐
Django ORM expressions can also be used as Filter references.
Remember that subqueries are also counted as expressions.
Function references๐
Functions (or methods) can also be used to create Filters.
This can be done by decorating a method with the Filter class.
These types of Filters should return a Q expression.
The type of the value argument is used as the input type for the Filter, so typing it is required.
About method signature
The decorated method is treated as a static method by the Filter.
The self argument is not an instance of the FilterSet,
but the instance of the Filter that is being used.
The info argument can be left out, but if it's included, it should always
have the GQLInfo type annotation.
The value argument is the value provided for the filter. It should always be named "value",
and is required to be a keyword only argument.
Lookup๐
By default, when a Filter is defined on a FilterSet, the "exact" lookup expression
is used. This can be changed by providing the lookup argument to the Filter.
Many๐
The many argument changes the behavior of a Filter such that it takes
a list of values instead of a single value. Then, each of the given values are combined
as defined by the match argument to form a single filter condition.
This would create the following filter input:
So if a query is filtered using this filter with the value ["foo", "bar"],
the filter condition would be Q(name__icontains="foo") | Q(name__icontains="bar").
Match๐
The match argument changes the behavior of the many argument to combine the
provided values with a different operation. The default is any, which means
that the filter condition will include an item if it matches any of the provided values.
The match argument can be set to all if all of the values should match,
or one_of if only one of the values should match.
Distinct๐
If using a Filter would require a call to queryset.distinct() to remove duplicates
(e.g. lookups spanning "to-many" relations), you can set the distinct argument to True.
Required๐
By default, all Filters are non-required (nullable in GraphQL terms).
If you want to make a Filter required, you can do so by setting the required argument to True.
Making a Filter required means that if any filtering is done on an Entrypoint of related Field
using a QueryType with the FilterSet this Filter belongs to, this Filter must be used in
addition to any other Filters you might want to use. It must also be used in any logical
blocks that users might want to make.
Aliases๐
Sometimes a Filter may require additional expressions to be added as aliases
to the queryset when the Filter is used. For this, you can define a function
that returns a dictionary of expressions and decorate it with the aliases decorator.
Empty values๐
By default, Filters will ignore some values which are considered "empty" in the context of filtering.
These values are set globally by the EMPTY_VALUES setting.
Usually this is what you want, as it allows you to set default values in your GraphQL variables.
If you wish to change what's considered an empty value for an individual Filter,
you can do so by setting the empty_values argument to a list of values.
Field name๐
A field_name can be provided to explicitly set the Django Model field
that the Filter corresponds to.
This can be useful when the Model field corresponding to the Filter
has a different name and type in the GraphQL schema than in the Model.
Schema name๐
By default, the name of the InputObjectType field generated from a Filter is the same
as the name of the Filter on the FilterSet class (converted to camelCase if
CAMEL_CASE_SCHEMA_FIELDS is enabled).
If you want to change the name of the InputObjectType field separately,
you can do so by setting the schema_name argument:
This can be useful when the desired name of the InputObjectType field is a Python keyword
and cannot be used as the Input attribute name.
Description๐
By default, a Filter is able to determine its description based on its reference.
For example, for a Model field, the description is taken from its help_text.
If the reference has no description, or you wish to add a different one,
this can be done in two ways:
1) By setting the description argument.
2) As class attribute docstrings, if ENABLE_CLASS_ATTRIBUTE_DOCSTRINGS is enabled.
When using function references, instead of a class attribute docstring, you add a docstring to the function/method used as the reference instead.
Deprecation reason๐
A deprecation_reason can be provided to mark the Filter as deprecated.
This is for documentation purposes only, and does not affect the use of the Filter.
Permissions๐
You can add permissions check to individual Filters by using Filter functions
and adding the permission check inline.
A special EmptyFilterResult exception can also be raised to indicate that
an empty queryset should be returned instead of an error.
Directives๐
You can add directives to the Filter by providing them using the directives argument.
You can also add them using the @ operator (which kind of looks like GraphQL syntax):
See the Directives section for more details on directives.
Visibility๐
This is an experimental feature that needs to be enabled using the
EXPERIMENTAL_VISIBILITY_CHECKSsetting.
You can hide a Filter from certain users by decorating a method with the
<filter_name>.visible decorator. Hiding a Filter means that it will not be included in introspection queries,
and trying to use it in operations will result in an error that looks exactly like
the Filter didn't exist in the first place.
GraphQL extensions๐
You can provide custom extensions for the Filter by providing a
extensions argument with a dictionary containing them. These can then be used
however you wish to extend the functionality of the Filter.
Filter extensions are made available in the GraphQL InputObjectType field extensions
after the schema is created. The Filter itself is found in the GraphQL input field extensions
under a key defined by the FILTER_EXTENSIONS_KEY
setting.