Skip to content

Commit acff3d5

Browse files
authored
Merge pull request #58 from tangerilli/recursive-nodes
Allow recursive connections with DjangoFilterConnectionField
2 parents fd91f78 + 57dbcd3 commit acff3d5

File tree

2 files changed

+76
-17
lines changed

2 files changed

+76
-17
lines changed

graphene_django/filter/fields.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,76 @@
1+
import inspect
2+
3+
from collections import OrderedDict
14
from functools import partial
25

6+
from graphene.types.argument import to_arguments
37
from ..fields import DjangoConnectionField
48
from graphene.relay import is_node
59
from .utils import get_filtering_args_from_filterset, get_filterset_class
610

711

812
class DjangoFilterConnectionField(DjangoConnectionField):
913

10-
def __init__(self, type, fields=None, extra_filter_meta=None,
11-
filterset_class=None, *args, **kwargs):
14+
def __init__(self, type, fields=None, order_by=None,
15+
extra_filter_meta=None, filterset_class=None,
16+
*args, **kwargs):
17+
self._fields = fields
18+
self._type = type
19+
self._filterset_class = filterset_class
20+
self._extra_filter_meta = extra_filter_meta
21+
self._base_args = None
22+
super(DjangoFilterConnectionField, self).__init__(type, *args, **kwargs)
23+
24+
@property
25+
def node_type(self):
26+
if inspect.isfunction(self._type) or inspect.ismethod(self._type):
27+
return self._type()
28+
return self._type
1229

13-
if is_node(type):
14-
_fields = type._meta.filter_fields
15-
_model = type._meta.model
30+
@property
31+
def meta(self):
32+
if is_node(self.node_type):
33+
_model = self.node_type._meta.model
1634
else:
1735
# ConnectionFields can also be passed Connections,
1836
# in which case, we need to use the Node of the connection
1937
# to get our relevant args.
20-
_fields = type._meta.node._meta.filter_fields
21-
_model = type._meta.node._meta.model
22-
23-
self.fields = fields or _fields
24-
meta = dict(model=_model, fields=self.fields)
25-
if extra_filter_meta:
26-
meta.update(extra_filter_meta)
27-
self.filterset_class = get_filterset_class(filterset_class, **meta)
28-
self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, type)
29-
kwargs.setdefault('args', {})
30-
kwargs['args'].update(self.filtering_args)
31-
super(DjangoFilterConnectionField, self).__init__(type, *args, **kwargs)
38+
_model = self.node_type._meta.node._meta.model
39+
40+
meta = dict(model=_model,
41+
fields=self.fields)
42+
if self._extra_filter_meta:
43+
meta.update(self._extra_filter_meta)
44+
return meta
45+
46+
@property
47+
def fields(self):
48+
if self._fields:
49+
return self._fields
50+
51+
if is_node(self.node_type):
52+
return self.node_type._meta.filter_fields
53+
else:
54+
# ConnectionFields can also be passed Connections,
55+
# in which case, we need to use the Node of the connection
56+
# to get our relevant args.
57+
return self.node_type._meta.node._meta.filter_fields
58+
59+
@property
60+
def args(self):
61+
return to_arguments(self._base_args or OrderedDict(), self.filtering_args)
62+
63+
@args.setter
64+
def args(self, args):
65+
self._base_args = args
66+
67+
@property
68+
def filterset_class(self):
69+
return get_filterset_class(self._filterset_class, **self.meta)
70+
71+
@property
72+
def filtering_args(self):
73+
return get_filtering_args_from_filterset(self.filterset_class, self.node_type)
3274

3375
@staticmethod
3476
def connection_resolver(resolver, connection, default_manager, filterset_class, filtering_args,

graphene_django/filter/tests/test_fields.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,20 @@ class Query(ObjectType):
348348
assert not result.errors
349349
# We should only get two reporters
350350
assert len(result.data['allReporters']['edges']) == 2
351+
352+
353+
def test_recursive_filter_connection():
354+
class ReporterFilterNode(DjangoObjectType):
355+
child_reporters = DjangoFilterConnectionField(lambda: ReporterFilterNode)
356+
357+
def resolve_child_reporters(self, args, context, info):
358+
return []
359+
360+
class Meta:
361+
model = Reporter
362+
interfaces = (Node, )
363+
364+
class Query(ObjectType):
365+
all_reporters = DjangoFilterConnectionField(ReporterFilterNode)
366+
367+
assert ReporterFilterNode._meta.fields['child_reporters'].node_type == ReporterFilterNode

0 commit comments

Comments
 (0)