Filtering¶
Graphene integrates with
django-filter (2.x for
Python 3 or 1.x for Python 2) to provide filtering of results. See the usage
documentation
for details on the format for filter_fields
.
This filtering is automatically available when implementing a relay.Node
.
Additionally django-filter
is an optional dependency of Graphene.
You will need to install it manually, which can be done as follows:
# You'll need to django-filter
pip install django-filter>=2
Note: The techniques below are demoed in the cookbook example app.
Filterable fields¶
The filter_fields
parameter is used to specify the fields which can
be filtered upon. The value specified here is passed directly to
django-filter
, so see the filtering
documentation
for full details on the range of options available.
For example:
class AnimalNode(DjangoObjectType):
class Meta:
# Assume you have an Animal model defined with the following fields
model = Animal
filter_fields = ['name', 'genus', 'is_domesticated']
interfaces = (relay.Node, )
class Query(ObjectType):
animal = relay.Node.Field(AnimalNode)
all_animals = DjangoFilterConnectionField(AnimalNode)
You could then perform a query such as:
query {
# Note that fields names become camelcased
allAnimals(genus: "cat", isDomesticated: true) {
edges {
node {
id,
name
}
}
}
}
You can also make more complex lookup types available:
class AnimalNode(DjangoObjectType):
class Meta:
model = Animal
# Provide more complex lookup types
filter_fields = {
'name': ['exact', 'icontains', 'istartswith'],
'genus': ['exact'],
'is_domesticated': ['exact'],
}
interfaces = (relay.Node, )
Which you could query as follows:
query {
# Note that fields names become camelcased
allAnimals(name_Icontains: "lion") {
edges {
node {
id,
name
}
}
}
}
Custom Filtersets¶
By default Graphene provides easy access to the most commonly used
features of django-filter
. This is done by transparently creating a
django_filters.FilterSet
class for you and passing in the values for
filter_fields
.
However, you may find this to be insufficient. In these cases you can
create your own Filterset
as follows:
class AnimalNode(DjangoObjectType):
class Meta:
# Assume you have an Animal model defined with the following fields
model = Animal
filter_fields = ['name', 'genus', 'is_domesticated']
interfaces = (relay.Node, )
class AnimalFilter(django_filters.FilterSet):
# Do case-insensitive lookups on 'name'
name = django_filters.CharFilter(lookup_expr=['iexact'])
class Meta:
model = Animal
fields = ['name', 'genus', 'is_domesticated']
class Query(ObjectType):
animal = relay.Node.Field(AnimalNode)
# We specify our custom AnimalFilter using the filterset_class param
all_animals = DjangoFilterConnectionField(AnimalNode,
filterset_class=AnimalFilter)
The context argument is passed on as the request argument
in a django_filters.FilterSet
instance. You can use this to customize your
filters to be context-dependent. We could modify the AnimalFilter
above to
pre-filter animals owned by the authenticated user (set in context.user
).
class AnimalFilter(django_filters.FilterSet):
# Do case-insensitive lookups on 'name'
name = django_filters.CharFilter(lookup_type='iexact')
class Meta:
model = Animal
fields = ['name', 'genus', 'is_domesticated']
@property
def qs(self):
# The query context can be found in self.request.
return super(AnimalFilter, self).qs.filter(owner=self.request.user)