Making GrapheneFilterSetMixin compatible with django_filter 2

This commit is contained in:
Jay Hale 2018-08-05 10:26:14 -04:00
parent 14f156ef5f
commit dc0c2900d1
4 changed files with 20 additions and 35 deletions

View File

@ -2,11 +2,9 @@ Filtering
=========
Graphene integrates with
`django-filter <https://django-filter.readthedocs.io/en/1.1.0/>`__ (< 2.0.0) to provide
filtering of results (this also means filtering is only compatible with Django < 2.0).
See the `usage
documentation <https://django-filter.readthedocs.io/en/1.1.0/guide/usage.html#the-filter>`__
`django-filter <https://django-filter.readthedocs.io/en/master/>`__ (2.x for
Python 3 or 1.x for Python 2) to provide filtering of results. See the `usage
documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
for details on the format for ``filter_fields``.
This filtering is automatically available when implementing a ``relay.Node``.
@ -17,7 +15,7 @@ You will need to install it manually, which can be done as follows:
.. code:: bash
# You'll need to django-filter
pip install django-filter==1.1.0
pip install django-filter>=2
Note: The techniques below are demoed in the `cookbook example
app <https://github.com/graphql-python/graphene-django/tree/master/examples/cookbook>`__.
@ -28,7 +26,7 @@ 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 <https://django-filter.readthedocs.io/en/1.1.0/guide/usage.html#the-filter>`__
documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
for full details on the range of options available.
For example:
@ -129,7 +127,7 @@ create your own ``Filterset`` as follows:
all_animals = DjangoFilterConnectionField(AnimalNode,
filterset_class=AnimalFilter)
The context argument is passed on as the `request argument <http://django-filter.readthedocs.io/en/1.1.0/guide/usage.html#request-based-filtering>`__
The context argument is passed on as the `request argument <http://django-filter.readthedocs.io/en/master/guide/usage.html#request-based-filtering>`__
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``).

View File

@ -2,4 +2,4 @@ graphene
graphene-django
graphql-core>=2.1rc1
django==1.9
django-filter<2
django-filter>=2

View File

@ -1,7 +1,6 @@
import itertools
from django.db import models
from django.utils.text import capfirst
from django_filters import Filter, MultipleChoiceFilter
from django_filters.filterset import BaseFilterSet, FilterSet
from django_filters.filterset import FILTER_FOR_DBFIELD_DEFAULTS
@ -15,7 +14,10 @@ class GlobalIDFilter(Filter):
field_class = GlobalIDFormField
def filter(self, qs, value):
_type, _id = from_global_id(value)
""" Convert the filter value to a primary key before filtering """
_id = None
if value is not None:
_, _id = from_global_id(value)
return super(GlobalIDFilter, self).filter(qs, _id)
@ -32,37 +34,22 @@ GRAPHENE_FILTER_SET_OVERRIDES = {
models.OneToOneField: {"filter_class": GlobalIDFilter},
models.ForeignKey: {"filter_class": GlobalIDFilter},
models.ManyToManyField: {"filter_class": GlobalIDMultipleChoiceFilter},
models.ManyToOneRel: {"filter_class": GlobalIDMultipleChoiceFilter},
models.ManyToManyRel: {"filter_class": GlobalIDMultipleChoiceFilter},
}
class GrapheneFilterSetMixin(BaseFilterSet):
""" A django_filters.filterset.BaseFilterSet with default filter overrides
to handle global IDs """
FILTER_DEFAULTS = dict(
itertools.chain(
FILTER_FOR_DBFIELD_DEFAULTS.items(), GRAPHENE_FILTER_SET_OVERRIDES.items()
FILTER_FOR_DBFIELD_DEFAULTS.items(),
GRAPHENE_FILTER_SET_OVERRIDES.items()
)
)
@classmethod
def filter_for_reverse_field(cls, f, name):
"""Handles retrieving filters for reverse relationships
We override the default implementation so that we can handle
Global IDs (the default implementation expects database
primary keys)
"""
try:
rel = f.field.remote_field
except AttributeError:
rel = f.field.rel
default = {"name": name, "label": capfirst(rel.related_name)}
if rel.multiple:
# For to-many relationships
return GlobalIDMultipleChoiceFilter(**default)
else:
# For to-one relationships
return GlobalIDFilter(**default)
def setup_filterset(filterset_class):
""" Wrap a provided filterset in Graphene-specific functionality

View File

@ -19,7 +19,7 @@ tests_require = [
"coveralls",
"mock",
"pytz",
"django-filter<2",
"django-filter>=2",
"pytest-django>=3.3.2",
] + rest_framework_require
@ -50,7 +50,7 @@ setup(
"six>=1.10.0",
"graphene>=2.1,<3",
"graphql-core>=2.1rc1",
"Django>=1.8.0",
"Django>=1.11",
"iso8601",
"singledispatch>=3.4.0.3",
"promise>=2.1",