Skip to content

Commit 5833cb8

Browse files
committed
Fixed filterset limit issue
1 parent 055c6e2 commit 5833cb8

File tree

3 files changed

+100
-10
lines changed

3 files changed

+100
-10
lines changed

graphene_django/fields.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,21 @@ def get_manager(self):
4646
else:
4747
return self.model._default_manager
4848

49-
@staticmethod
50-
def connection_resolver(resolver, connection, default_manager, root, args, context, info):
49+
@classmethod
50+
def merge_querysets(cls, default_queryset, queryset):
51+
return default_queryset & queryset
52+
53+
@classmethod
54+
def connection_resolver(cls, resolver, connection, default_manager, root, args, context, info):
5155
iterable = resolver(root, args, context, info)
5256
if iterable is None:
5357
iterable = default_manager
5458
iterable = maybe_queryset(iterable)
5559
if isinstance(iterable, QuerySet):
5660
if iterable is not default_manager:
57-
iterable = list(set(iterable).intersection(maybe_queryset(default_manager)))
58-
_len = len(iterable)
59-
else:
60-
_len = iterable.count()
61+
default_queryset = maybe_queryset(default_manager)
62+
iterable = cls.merge_querysets(default_queryset, iterable)
63+
_len = iterable.count()
6164
else:
6265
_len = len(iterable)
6366
connection = connection_from_list_slice(

graphene_django/filter/fields.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,37 @@ def filtering_args(self):
4545
return get_filtering_args_from_filterset(self.filterset_class, self.node_type)
4646

4747
@staticmethod
48-
def connection_resolver(resolver, connection, default_manager, filterset_class, filtering_args,
48+
def merge_querysets(default_queryset, queryset):
49+
# There could be the case where the default queryset (returned from the filterclass)
50+
# and the resolver queryset have some limits on it.
51+
# We only would be able to apply one of those, but not both
52+
# at the same time.
53+
54+
# See related PR: https://github.com/graphql-python/graphene-django/pull/126
55+
56+
assert not (default_queryset.query.low_mark and queryset.query.low_mark), (
57+
'Received two sliced querysets (low mark) in the connection, please slice only in one.'
58+
)
59+
assert not (default_queryset.query.high_mark and queryset.query.high_mark), (
60+
'Received two sliced querysets (high mark) in the connection, please slice only in one.'
61+
)
62+
low = default_queryset.query.low_mark or queryset.query.low_mark
63+
high = default_queryset.query.high_mark or queryset.query.high_mark
64+
default_queryset.query.clear_limits()
65+
queryset = default_queryset & queryset
66+
queryset.query.set_limits(low, high)
67+
return queryset
68+
69+
@classmethod
70+
def connection_resolver(cls, resolver, connection, default_manager, filterset_class, filtering_args,
4971
root, args, context, info):
5072
filter_kwargs = {k: v for k, v in args.items() if k in filtering_args}
5173
qs = filterset_class(
5274
data=filter_kwargs,
5375
queryset=default_manager.get_queryset()
5476
).qs
55-
return DjangoConnectionField.connection_resolver(resolver, connection, qs, root, args, context, info)
77+
return super(DjangoFilterConnectionField, cls).connection_resolver(
78+
resolver, connection, qs, root, args, context, info)
5679

5780
def get_resolver(self, parent_resolver):
5881
return partial(self.connection_resolver, parent_resolver, self.type, self.get_manager(),

graphene_django/tests/test_query.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,10 +525,12 @@ def resolve_all_reporters(self, args, context, info):
525525
edges {
526526
node {
527527
id
528+
firstName
528529
articles(lang: "es") {
529530
edges {
530531
node {
531532
id
533+
lang
532534
}
533535
}
534536
}
@@ -542,11 +544,13 @@ def resolve_all_reporters(self, args, context, info):
542544
'allReporters': {
543545
'edges': [{
544546
'node': {
545-
'id': 'UmVwb3J0ZXJUeXBlOjE=',
547+
'id': 'UmVwb3J0ZXJUeXBlOjI=',
548+
'firstName': 'John',
546549
'articles': {
547550
'edges': [{
548551
'node': {
549-
'id': 'QXJ0aWNsZVR5cGU6MQ=='
552+
'id': 'QXJ0aWNsZVR5cGU6MQ==',
553+
'lang': 'ES'
550554
}
551555
}]
552556
}
@@ -558,3 +562,63 @@ def resolve_all_reporters(self, args, context, info):
558562
result = schema.execute(query)
559563
assert not result.errors
560564
assert result.data == expected
565+
566+
567+
def test_should_query_filter_node_double_limit_raises():
568+
class ReporterFilter(FilterSet):
569+
limit = NumberFilter(method='filter_limit')
570+
571+
def filter_limit(self, queryset, name, value):
572+
return queryset[:value]
573+
574+
class Meta:
575+
model = Reporter
576+
fields = ['first_name', ]
577+
578+
class ReporterType(DjangoObjectType):
579+
580+
class Meta:
581+
model = Reporter
582+
interfaces = (Node, )
583+
584+
class Query(graphene.ObjectType):
585+
all_reporters = DjangoFilterConnectionField(
586+
ReporterType,
587+
filterset_class=ReporterFilter
588+
)
589+
590+
def resolve_all_reporters(self, args, context, info):
591+
return Reporter.objects.order_by('a_choice')[:2]
592+
593+
Reporter.objects.create(
594+
first_name='Bob',
595+
last_name='Doe',
596+
597+
a_choice=2
598+
)
599+
r = Reporter.objects.create(
600+
first_name='John',
601+
last_name='Doe',
602+
603+
a_choice=1
604+
)
605+
606+
schema = graphene.Schema(query=Query)
607+
query = '''
608+
query NodeFilteringQuery {
609+
allReporters(limit: 1) {
610+
edges {
611+
node {
612+
id
613+
firstName
614+
}
615+
}
616+
}
617+
}
618+
'''
619+
620+
result = schema.execute(query)
621+
assert len(result.errors) == 1
622+
assert str(result.errors[0]) == (
623+
'Received two sliced querysets (high mark) in the connection, please slice only in one.'
624+
)

0 commit comments

Comments
 (0)