Skip to content

Commit e1145b8

Browse files
committed
Improved resolvers in Django
1 parent 33c58f6 commit e1145b8

File tree

9 files changed

+96
-255
lines changed

9 files changed

+96
-255
lines changed

graphene/contrib/django/fields.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,44 @@
1-
import warnings
2-
31
from ...core.exceptions import SkipField
42
from ...core.fields import Field
53
from ...core.types.base import FieldType
64
from ...core.types.definitions import List
75
from ...relay import ConnectionField
86
from ...relay.utils import is_node
9-
from .filter.fields import DjangoFilterConnectionField
10-
from .utils import get_type_for_model
7+
from .utils import get_type_for_model, maybe_queryset
118

129

1310
class DjangoConnectionField(ConnectionField):
1411

1512
def __init__(self, *args, **kwargs):
16-
cls = self.__class__
17-
warnings.warn("Using {} will be not longer supported."
18-
" Use relay.ConnectionField instead".format(cls.__name__),
19-
FutureWarning)
13+
self.on = kwargs.pop('on', False)
2014
return super(DjangoConnectionField, self).__init__(*args, **kwargs)
2115

16+
@property
17+
def model(self):
18+
return self.type._meta.model
19+
20+
def get_manager(self):
21+
if self.on:
22+
return getattr(self.model, self.on)
23+
else:
24+
return self.model._default_manager
25+
26+
def get_queryset(self, resolved_qs, args, info):
27+
return resolved_qs
28+
29+
def from_list(self, connection_type, resolved, args, info):
30+
if not resolved:
31+
resolved = self.get_manager()
32+
resolved_qs = maybe_queryset(resolved)
33+
qs = self.get_queryset(resolved_qs, args, info)
34+
return super(DjangoConnectionField, self).from_list(connection_type, qs, args, info)
35+
2236

2337
class ConnectionOrListField(Field):
2438

2539
def internal_type(self, schema):
40+
from .filter.fields import DjangoFilterConnectionField
41+
2642
model_field = self.type
2743
field_object_type = model_field.get_object_type(schema)
2844
if not field_object_type:
@@ -31,7 +47,7 @@ def internal_type(self, schema):
3147
if field_object_type._meta.filter_fields:
3248
field = DjangoFilterConnectionField(field_object_type)
3349
else:
34-
field = ConnectionField(field_object_type)
50+
field = DjangoConnectionField(field_object_type)
3551
else:
3652
field = Field(List(field_object_type))
3753
field.contribute_to_class(self.object_type, self.attname)
Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
1-
from graphene.contrib.django.filter.resolvers import FilterConnectionResolver
2-
from graphene.contrib.django.utils import get_filtering_args_from_filterset
3-
from graphene.relay import ConnectionField
1+
from .utils import get_filterset_class, get_filtering_args_from_filterset
2+
from ..fields import DjangoConnectionField
43

54

6-
class DjangoFilterConnectionField(ConnectionField):
5+
class DjangoFilterConnectionField(DjangoConnectionField):
76

8-
def __init__(self, type, on=None, fields=None, order_by=None,
9-
extra_filter_meta=None, filterset_class=None, resolver=None,
7+
def __init__(self, type, fields=None, order_by=None,
8+
extra_filter_meta=None, filterset_class=None,
109
*args, **kwargs):
1110

12-
if not resolver:
13-
resolver = FilterConnectionResolver(
14-
node=type,
15-
on=on,
16-
filterset_class=filterset_class,
17-
fields=fields,
18-
order_by=order_by,
19-
extra_filter_meta=extra_filter_meta,
20-
)
21-
22-
filtering_args = get_filtering_args_from_filterset(resolver.get_filterset_class(), type)
11+
self.order_by = order_by or type._meta.filter_order_by
12+
self.fields = fields or type._meta.filter_fields
13+
meta = dict(model=type._meta.model,
14+
fields=self.fields,
15+
order_by=self.order_by)
16+
if extra_filter_meta:
17+
meta.update(extra_filter_meta)
18+
self.filterset_class = get_filterset_class(filterset_class, **meta)
19+
self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, type)
2320
kwargs.setdefault('args', {})
24-
kwargs['args'].update(**filtering_args)
25-
super(DjangoFilterConnectionField, self).__init__(type, resolver, *args, **kwargs)
21+
kwargs['args'].update(**self.filtering_args)
22+
super(DjangoFilterConnectionField, self).__init__(type, *args, **kwargs)
23+
24+
def get_queryset(self, qs, args, info):
25+
filterset_class = self.filterset_class
26+
filter_kwargs = self.get_filter_kwargs(args)
27+
order = self.get_order(args)
28+
if order:
29+
qs = qs.order_by(order)
30+
return filterset_class(data=filter_kwargs, queryset=qs)
31+
32+
def get_filter_kwargs(self, args):
33+
return {k: v for k, v in args.items() if k in self.filtering_args}
34+
35+
def get_order(self, args):
36+
return args.get('order_by', None)

graphene/contrib/django/filter/resolvers.py

Lines changed: 0 additions & 64 deletions
This file was deleted.

graphene/contrib/django/filter/tests/test_fields.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
GlobalIDMultipleChoiceField)
1010
from graphene.contrib.django.tests.models import Article, Pet, Reporter
1111
from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
12-
from graphene.relay import NodeField
12+
from graphene.relay import NodeField, ConnectionField
1313
from graphene.utils import ProxySnakeDict
1414

1515
pytestmark = []
@@ -217,7 +217,7 @@ class Query(ObjectType):
217217

218218
def test_global_id_field_implicit():
219219
field = DjangoFilterConnectionField(ArticleNode, fields=['id'])
220-
filterset_class = field.resolver_fn.get_filterset_class()
220+
filterset_class = field.filterset_class
221221
id_filter = filterset_class.base_filters['id']
222222
assert isinstance(id_filter, GlobalIDFilter)
223223
assert id_filter.field_class == GlobalIDFormField
@@ -231,23 +231,23 @@ class Meta:
231231
fields = ['id']
232232

233233
field = DjangoFilterConnectionField(ArticleNode, filterset_class=ArticleIdFilter)
234-
filterset_class = field.resolver_fn.get_filterset_class()
234+
filterset_class = field.filterset_class
235235
id_filter = filterset_class.base_filters['id']
236236
assert isinstance(id_filter, GlobalIDFilter)
237237
assert id_filter.field_class == GlobalIDFormField
238238

239239

240240
def test_global_id_field_relation():
241241
field = DjangoFilterConnectionField(ArticleNode, fields=['reporter'])
242-
filterset_class = field.resolver_fn.get_filterset_class()
242+
filterset_class = field.filterset_class
243243
id_filter = filterset_class.base_filters['reporter']
244244
assert isinstance(id_filter, GlobalIDFilter)
245245
assert id_filter.field_class == GlobalIDFormField
246246

247247

248248
def test_global_id_multiple_field_implicit():
249249
field = DjangoFilterConnectionField(ReporterNode, fields=['pets'])
250-
filterset_class = field.resolver_fn.get_filterset_class()
250+
filterset_class = field.filterset_class
251251
multiple_filter = filterset_class.base_filters['pets']
252252
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
253253
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
@@ -261,15 +261,15 @@ class Meta:
261261
fields = ['pets']
262262

263263
field = DjangoFilterConnectionField(ReporterNode, filterset_class=ReporterPetsFilter)
264-
filterset_class = field.resolver_fn.get_filterset_class()
264+
filterset_class = field.filterset_class
265265
multiple_filter = filterset_class.base_filters['pets']
266266
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
267267
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
268268

269269

270270
def test_global_id_multiple_field_implicit_reverse():
271271
field = DjangoFilterConnectionField(ReporterNode, fields=['articles'])
272-
filterset_class = field.resolver_fn.get_filterset_class()
272+
filterset_class = field.filterset_class
273273
multiple_filter = filterset_class.base_filters['articles']
274274
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
275275
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
@@ -283,7 +283,7 @@ class Meta:
283283
fields = ['articles']
284284

285285
field = DjangoFilterConnectionField(ReporterNode, filterset_class=ReporterPetsFilter)
286-
filterset_class = field.resolver_fn.get_filterset_class()
286+
filterset_class = field.filterset_class
287287
multiple_filter = filterset_class.base_filters['articles']
288288
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
289289
assert multiple_filter.field_class == GlobalIDMultipleChoiceField

graphene/contrib/django/filter/tests/test_resolvers.py

Lines changed: 0 additions & 82 deletions
This file was deleted.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import six
2+
3+
from .filterset import custom_filterset_factory, setup_filterset
4+
from ....core.types import Argument, String
5+
6+
7+
def get_filtering_args_from_filterset(filterset_class, type):
8+
""" Inspect a FilterSet and produce the arguments to pass to
9+
a Graphene Field. These arguments will be available to
10+
filter against in the GraphQL
11+
"""
12+
from graphene.contrib.django.form_converter import convert_form_field
13+
14+
args = {}
15+
for name, filter_field in six.iteritems(filterset_class.base_filters):
16+
field_type = Argument(convert_form_field(filter_field.field))
17+
args[name] = field_type
18+
19+
# Also add the 'order_by' field
20+
if filterset_class._meta.order_by:
21+
args[filterset_class.order_by_field] = Argument(String())
22+
return args
23+
24+
25+
def get_filterset_class(filterset_class, **meta):
26+
"""Get the class to be used as the FilterSet"""
27+
if filterset_class:
28+
# If were given a FilterSet class, then set it up and
29+
# return it
30+
return setup_filterset(filterset_class)
31+
return custom_filterset_factory(**meta)

0 commit comments

Comments
 (0)