Skip to content

Commit 314703d

Browse files
committed
Improved querying and slicing in DjangoConnectionFields and inherited. Fixed #108
1 parent c5b15ce commit 314703d

File tree

6 files changed

+197
-38
lines changed

6 files changed

+197
-38
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,39 @@
11
import pytest
22

33
import graphene
4-
from graphene.contrib.django import DjangoObjectType
4+
from graphene.contrib.django import DjangoNode, DjangoConnectionField
5+
from graphene.contrib.django.filter import DjangoFilterConnectionField
56

67
from ...tests.models import Reporter
78
from ..plugin import DjangoDebugPlugin
89

910
# from examples.starwars_django.models import Character
1011

12+
from django.db.models import Count
13+
1114
pytestmark = pytest.mark.django_db
1215

1316

14-
def test_should_query_well():
17+
def count(qs):
18+
query = qs.query
19+
query.add_annotation(Count('*'), alias='__count', is_summary=True)
20+
query.select = []
21+
query.default_cols = False
22+
return query
23+
24+
25+
def test_should_query_field():
1526
r1 = Reporter(last_name='ABA')
1627
r1.save()
1728
r2 = Reporter(last_name='Griffin')
1829
r2.save()
1930

20-
class ReporterType(DjangoObjectType):
21-
31+
class ReporterType(DjangoNode):
2232
class Meta:
2333
model = Reporter
2434

2535
class Query(graphene.ObjectType):
2636
reporter = graphene.Field(ReporterType)
27-
all_reporters = ReporterType.List()
28-
29-
def resolve_all_reporters(self, *args, **kwargs):
30-
return Reporter.objects.all()
3137

3238
def resolve_reporter(self, *args, **kwargs):
3339
return Reporter.objects.first()
@@ -37,9 +43,6 @@ def resolve_reporter(self, *args, **kwargs):
3743
reporter {
3844
lastName
3945
}
40-
allReporters {
41-
lastName
42-
}
4346
__debug {
4447
sql {
4548
rawSql
@@ -51,15 +54,55 @@ def resolve_reporter(self, *args, **kwargs):
5154
'reporter': {
5255
'lastName': 'ABA',
5356
},
57+
'__debug': {
58+
'sql': [{
59+
'rawSql': str(Reporter.objects.order_by('pk')[:1].query)
60+
}]
61+
}
62+
}
63+
schema = graphene.Schema(query=Query, plugins=[DjangoDebugPlugin()])
64+
result = schema.execute(query)
65+
assert not result.errors
66+
assert result.data == expected
67+
68+
69+
def test_should_query_list():
70+
r1 = Reporter(last_name='ABA')
71+
r1.save()
72+
r2 = Reporter(last_name='Griffin')
73+
r2.save()
74+
75+
class ReporterType(DjangoNode):
76+
77+
class Meta:
78+
model = Reporter
79+
80+
class Query(graphene.ObjectType):
81+
all_reporters = ReporterType.List()
82+
83+
def resolve_all_reporters(self, *args, **kwargs):
84+
return Reporter.objects.all()
85+
86+
query = '''
87+
query ReporterQuery {
88+
allReporters {
89+
lastName
90+
}
91+
__debug {
92+
sql {
93+
rawSql
94+
}
95+
}
96+
}
97+
'''
98+
expected = {
5499
'allReporters': [{
55100
'lastName': 'ABA',
56101
}, {
57102
'lastName': 'Griffin',
58103
}],
59104
'__debug': {
60105
'sql': [{
61-
'rawSql': str(Reporter.objects.order_by('pk')[:1].query)
62-
}, {
63106
'rawSql': str(Reporter.objects.all().query)
64107
}]
65108
}
@@ -68,3 +111,122 @@ def resolve_reporter(self, *args, **kwargs):
68111
result = schema.execute(query)
69112
assert not result.errors
70113
assert result.data == expected
114+
115+
116+
def test_should_query_connection():
117+
r1 = Reporter(last_name='ABA')
118+
r1.save()
119+
r2 = Reporter(last_name='Griffin')
120+
r2.save()
121+
122+
class ReporterType(DjangoNode):
123+
124+
class Meta:
125+
model = Reporter
126+
127+
class Query(graphene.ObjectType):
128+
all_reporters_connection = DjangoConnectionField(ReporterType)
129+
130+
def resolve_all_reporters_connection(self, *args, **kwargs):
131+
return Reporter.objects.all()
132+
133+
query = '''
134+
query ReporterQuery {
135+
allReportersConnection(first:1) {
136+
edges {
137+
node {
138+
lastName
139+
}
140+
}
141+
}
142+
__debug {
143+
sql {
144+
rawSql
145+
}
146+
}
147+
}
148+
'''
149+
expected = {
150+
'allReportersConnection': {
151+
'edges': [{
152+
'node': {
153+
'lastName': 'ABA',
154+
}
155+
}]
156+
},
157+
'__debug': {
158+
'sql': [{
159+
'rawSql': str(count(Reporter.objects.all()))
160+
}, {
161+
'rawSql': str(Reporter.objects.all()[:1].query)
162+
}]
163+
}
164+
}
165+
schema = graphene.Schema(query=Query, plugins=[DjangoDebugPlugin()])
166+
result = schema.execute(query)
167+
assert not result.errors
168+
assert result.data == expected
169+
170+
171+
def test_should_query_connectionfilter():
172+
r1 = Reporter(last_name='ABA')
173+
r1.save()
174+
r2 = Reporter(last_name='Griffin')
175+
r2.save()
176+
177+
class ReporterType(DjangoNode):
178+
179+
class Meta:
180+
model = Reporter
181+
182+
class Query(graphene.ObjectType):
183+
all_reporters_connection_filter = DjangoFilterConnectionField(ReporterType)
184+
185+
def resolve_all_reporters_connection_filter(self, *args, **kwargs):
186+
return Reporter.objects.all()
187+
188+
def resolve_all_reporters_connection(self, *args, **kwargs):
189+
return Reporter.objects.all()
190+
191+
def resolve_all_reporters(self, *args, **kwargs):
192+
return Reporter.objects.all()
193+
194+
def resolve_reporter(self, *args, **kwargs):
195+
return Reporter.objects.first()
196+
197+
query = '''
198+
query ReporterQuery {
199+
allReportersConnectionFilter(first:1) {
200+
edges {
201+
node {
202+
lastName
203+
}
204+
}
205+
}
206+
__debug {
207+
sql {
208+
rawSql
209+
}
210+
}
211+
}
212+
'''
213+
expected = {
214+
'allReportersConnectionFilter': {
215+
'edges': [{
216+
'node': {
217+
'lastName': 'ABA',
218+
}
219+
}]
220+
},
221+
'__debug': {
222+
'sql': [{
223+
'rawSql': str(count(Reporter.objects.all()))
224+
}, {
225+
'rawSql': str(Reporter.objects.all()[:1].query)
226+
}]
227+
}
228+
}
229+
schema = graphene.Schema(query=Query, plugins=[DjangoDebugPlugin()])
230+
result = schema.execute(query)
231+
assert not result.errors
232+
assert result.data == expected

graphene/contrib/django/fields.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def get_queryset(self, resolved_qs, args, info):
2727
return resolved_qs
2828

2929
def from_list(self, connection_type, resolved, args, info):
30-
if not resolved:
30+
if resolved is None:
3131
resolved = self.get_manager()
3232
resolved_qs = maybe_queryset(resolved)
3333
qs = self.get_queryset(resolved_qs, args, info)

graphene/contrib/django/types.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,14 @@ class Meta:
5252
abstract = True
5353

5454
def __init__(self, _root=None):
55-
if _root:
56-
assert isinstance(_root, self._meta.model), (
57-
'{} received a non-compatible instance ({}) '
58-
'when expecting {}'.format(
59-
self.__class__.__name__,
60-
_root.__class__.__name__,
61-
self._meta.model.__name__
62-
))
6355
super(InstanceObjectType, self).__init__(_root=_root)
56+
assert not self._root or isinstance(self._root, self._meta.model), (
57+
'{} received a non-compatible instance ({}) '
58+
'when expecting {}'.format(
59+
self.__class__.__name__,
60+
self._root.__class__.__name__,
61+
self._meta.model.__name__
62+
))
6463

6564
@property
6665
def instance(self):
@@ -70,9 +69,6 @@ def instance(self):
7069
def instance(self, value):
7170
self._root = value
7271

73-
def __getattr__(self, attr):
74-
return getattr(self._root, attr)
75-
7672

7773
class DjangoObjectType(six.with_metaclass(
7874
DjangoObjectTypeMeta, InstanceObjectType)):

graphene/contrib/sqlalchemy/types.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,14 @@ class Meta:
6565
abstract = True
6666

6767
def __init__(self, _root=None):
68-
if _root:
69-
assert isinstance(_root, self._meta.model), (
70-
'{} received a non-compatible instance ({}) '
71-
'when expecting {}'.format(
72-
self.__class__.__name__,
73-
_root.__class__.__name__,
74-
self._meta.model.__name__
75-
))
7668
super(InstanceObjectType, self).__init__(_root=_root)
69+
assert not self._root or isinstance(self._root, self._meta.model), (
70+
'{} received a non-compatible instance ({}) '
71+
'when expecting {}'.format(
72+
self.__class__.__name__,
73+
self._root.__class__.__name__,
74+
self._meta.model.__name__
75+
))
7776

7877
@property
7978
def instance(self):
@@ -83,9 +82,6 @@ def instance(self):
8382
def instance(self, value):
8483
self._root = value
8584

86-
def __getattr__(self, attr):
87-
return getattr(self._root, attr)
88-
8985

9086
class SQLAlchemyObjectType(six.with_metaclass(
9187
SQLAlchemyObjectTypeMeta, InstanceObjectType)):

graphene/core/classtypes/objecttype.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ class Meta:
4747
abstract = True
4848

4949
def __getattr__(self, name):
50-
return self._root and getattr(self._root, name)
50+
if name != '_root' and self._root:
51+
return getattr(self._root, name)
5152

5253
def __init__(self, *args, **kwargs):
5354
signals.pre_init.send(self.__class__, args=args, kwargs=kwargs)

graphene/core/types/field.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ def contribute_to_class(self, cls, attname):
5757

5858
@property
5959
def resolver(self):
60-
return self.resolver_fn or self.get_resolver_fn()
60+
resolver = self.get_resolver_fn()
61+
return resolver
6162

6263
@property
6364
def default(self):
@@ -70,6 +71,9 @@ def default(self, value):
7071
self._default = value
7172

7273
def get_resolver_fn(self):
74+
if self.resolver_fn:
75+
return self.resolver_fn
76+
7377
resolve_fn_name = 'resolve_%s' % self.attname
7478
if hasattr(self.object_type, resolve_fn_name):
7579
return getattr(self.object_type, resolve_fn_name)

0 commit comments

Comments
 (0)