From 3e5ae5a3d1b60f3adcd7d1ba4583d94d23dc690a Mon Sep 17 00:00:00 2001 From: Tony Angerilli Date: Fri, 21 Oct 2016 00:20:49 -0700 Subject: [PATCH 1/5] =?UTF-8?q?don=E2=80=99t=20try=20to=20access=20the=20t?= =?UTF-8?q?ype=20until=20after=20initialization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this allows for fields in a node (using a DjangoFilterConnectionField) that reference themselves --- graphene_django/filter/fields.py | 55 ++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index bd4b44d..c0a91ce 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -1,5 +1,7 @@ +from collections import OrderedDict from functools import partial +from graphene.types.argument import to_arguments from ..fields import DjangoConnectionField from .utils import get_filtering_args_from_filterset, get_filterset_class @@ -9,19 +11,52 @@ class DjangoFilterConnectionField(DjangoConnectionField): def __init__(self, type, fields=None, order_by=None, extra_filter_meta=None, filterset_class=None, *args, **kwargs): + self._order_by = order_by + self._fields = fields + self._type = type + self._filterset_class = filterset_class + self._extra_filter_meta = extra_filter_meta + self._base_args = None + super(DjangoFilterConnectionField, self).__init__(type, *args, **kwargs) - self.order_by = order_by or type._meta.filter_order_by - self.fields = fields or type._meta.filter_fields - meta = dict(model=type._meta.model, + @property + def node_type(self): + if callable(self._type): + return self._type() + return self._type + + @property + def order_by(self): + return self._order_by or self.node_type._meta.filter_order_by + + @property + def meta(self): + meta = dict(model=self.node_type._meta.model, fields=self.fields, order_by=self.order_by) - if extra_filter_meta: - meta.update(extra_filter_meta) - self.filterset_class = get_filterset_class(filterset_class, **meta) - self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, type) - kwargs.setdefault('args', {}) - kwargs['args'].update(self.filtering_args) - super(DjangoFilterConnectionField, self).__init__(type, *args, **kwargs) + if self._extra_filter_meta: + meta.update(self.extra_filter_meta) + return meta + + @property + def fields(self): + return self._fields or self.node_type._meta.filter_fields + + @property + def args(self): + return to_arguments(self._base_args or OrderedDict(), self.filtering_args) + + @args.setter + def args(self, args): + self._base_args = args + + @property + def filterset_class(self): + return get_filterset_class(self._filterset_class, **self.meta) + + @property + def filtering_args(self): + return get_filtering_args_from_filterset(self.filterset_class, self.node_type) @staticmethod def connection_resolver(resolver, connection, default_manager, filterset_class, filtering_args, From dc6e8f110abaa80f8b8f9cc34be801ad7b87c3fa Mon Sep 17 00:00:00 2001 From: Tony Angerilli Date: Mon, 14 Nov 2016 10:40:47 -0800 Subject: [PATCH 2/5] fix typo --- graphene_django/filter/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index c0a91ce..9fa6130 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -35,7 +35,7 @@ class DjangoFilterConnectionField(DjangoConnectionField): fields=self.fields, order_by=self.order_by) if self._extra_filter_meta: - meta.update(self.extra_filter_meta) + meta.update(self._extra_filter_meta) return meta @property From 207f4ebb417934ba5194278c738396fe2c8bb4fd Mon Sep 17 00:00:00 2001 From: Tony Angerilli Date: Mon, 14 Nov 2016 23:44:50 -0800 Subject: [PATCH 3/5] added a test and made the type property better --- graphene_django/filter/fields.py | 4 +++- graphene_django/filter/tests/test_fields.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index 9fa6130..7e632a7 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -1,3 +1,5 @@ +import inspect + from collections import OrderedDict from functools import partial @@ -21,7 +23,7 @@ class DjangoFilterConnectionField(DjangoConnectionField): @property def node_type(self): - if callable(self._type): + if inspect.isfunction(self._type) or inspect.ismethod(self._type): return self._type() return self._type diff --git a/graphene_django/filter/tests/test_fields.py b/graphene_django/filter/tests/test_fields.py index ab3d677..ba1d8fc 100644 --- a/graphene_django/filter/tests/test_fields.py +++ b/graphene_django/filter/tests/test_fields.py @@ -350,3 +350,20 @@ def test_filter_filterset_related_results(): assert not result.errors # We should only get two reporters assert len(result.data['allReporters']['edges']) == 2 + + +def test_recursive_filter_connection(): + class ReporterFilterNode(DjangoObjectType): + child_reporters = DjangoFilterConnectionField(lambda: ReporterFilterNode) + + def resolve_child_reporters(self, args, context, info): + return [] + + class Meta: + model = Reporter + interfaces = (Node, ) + + class Query(ObjectType): + all_reporters = DjangoFilterConnectionField(ReporterFilterNode) + + assert ReporterFilterNode._meta.fields['child_reporters'].node_type == ReporterFilterNode From 9b1c1b4baddfbcde22a0ddd8b36df2b57546ed5c Mon Sep 17 00:00:00 2001 From: Elena Date: Mon, 23 Jan 2017 17:40:07 -0800 Subject: [PATCH 4/5] adding the option of defining a filterset_class in the Meta class --- graphene_django/filter/fields.py | 6 +++++- graphene_django/types.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index 83907e7..c2905ee 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -48,7 +48,11 @@ class DjangoFilterConnectionField(DjangoConnectionField): @property def filterset_class(self): - return get_filterset_class(self._filterset_class, **self.meta) + if self.node_type()._meta.filterset_class: + filterset_class = self.node_type()._meta.filterset_class + else: + filterset_class = get_filterset_class(self._filterset_class, **self.meta) + return filterset_class @property def filtering_args(self): diff --git a/graphene_django/types.py b/graphene_django/types.py index 8174f05..3710710 100644 --- a/graphene_django/types.py +++ b/graphene_django/types.py @@ -58,7 +58,8 @@ class DjangoObjectTypeMeta(ObjectTypeMeta): only_fields=(), exclude_fields=(), interfaces=(), - registry=None + registry=None, + filterset_class=None ) if DJANGO_FILTER_INSTALLED: # In case Django filter is available, then From e82ee8816c1456fca635c3b958a54b747560b430 Mon Sep 17 00:00:00 2001 From: Tony Angerilli Date: Mon, 23 Jan 2017 22:18:09 -0800 Subject: [PATCH 5/5] Revert "adding the option of defining a filterset_class in the Meta class" This reverts commit 9b1c1b4baddfbcde22a0ddd8b36df2b57546ed5c. --- graphene_django/filter/fields.py | 6 +----- graphene_django/types.py | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index c2905ee..83907e7 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -48,11 +48,7 @@ class DjangoFilterConnectionField(DjangoConnectionField): @property def filterset_class(self): - if self.node_type()._meta.filterset_class: - filterset_class = self.node_type()._meta.filterset_class - else: - filterset_class = get_filterset_class(self._filterset_class, **self.meta) - return filterset_class + return get_filterset_class(self._filterset_class, **self.meta) @property def filtering_args(self): diff --git a/graphene_django/types.py b/graphene_django/types.py index 3710710..8174f05 100644 --- a/graphene_django/types.py +++ b/graphene_django/types.py @@ -58,8 +58,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta): only_fields=(), exclude_fields=(), interfaces=(), - registry=None, - filterset_class=None + registry=None ) if DJANGO_FILTER_INSTALLED: # In case Django filter is available, then