1import datetime
2from django.db.models import Count
3
4import pytest
5
6from graphene import List, NonNull, ObjectType, Schema, String
7
8from ..fields import DjangoListField
9from ..types import DjangoObjectType
10from .models import Article as ArticleModel
11from .models import Reporter as ReporterModel
12
13
14class TestDjangoListField:
15    def test_only_django_object_types(self):
16        class TestType(ObjectType):
17            foo = String()
18
19        with pytest.raises(AssertionError):
20            list_field = DjangoListField(TestType)
21
22    def test_only_import_paths(self):
23        list_field = DjangoListField("graphene_django.tests.schema.Human")
24        from .schema import Human
25
26        assert list_field._type.of_type.of_type is Human
27
28    def test_non_null_type(self):
29        class Reporter(DjangoObjectType):
30            class Meta:
31                model = ReporterModel
32                fields = ("first_name",)
33
34        list_field = DjangoListField(NonNull(Reporter))
35
36        assert isinstance(list_field.type, List)
37        assert isinstance(list_field.type.of_type, NonNull)
38        assert list_field.type.of_type.of_type is Reporter
39
40    def test_get_django_model(self):
41        class Reporter(DjangoObjectType):
42            class Meta:
43                model = ReporterModel
44                fields = ("first_name",)
45
46        list_field = DjangoListField(Reporter)
47        assert list_field.model is ReporterModel
48
49    def test_list_field_default_queryset(self):
50        class Reporter(DjangoObjectType):
51            class Meta:
52                model = ReporterModel
53                fields = ("first_name",)
54
55        class Query(ObjectType):
56            reporters = DjangoListField(Reporter)
57
58        schema = Schema(query=Query)
59
60        query = """
61            query {
62                reporters {
63                    firstName
64                }
65            }
66        """
67
68        ReporterModel.objects.create(first_name="Tara", last_name="West")
69        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
70
71        result = schema.execute(query)
72
73        assert not result.errors
74        assert result.data == {
75            "reporters": [{"firstName": "Tara"}, {"firstName": "Debra"}]
76        }
77
78    def test_list_field_queryset_is_not_cached(self):
79        class Reporter(DjangoObjectType):
80            class Meta:
81                model = ReporterModel
82                fields = ("first_name",)
83
84        class Query(ObjectType):
85            reporters = DjangoListField(Reporter)
86
87        schema = Schema(query=Query)
88
89        query = """
90            query {
91                reporters {
92                    firstName
93                }
94            }
95        """
96
97        result = schema.execute(query)
98        assert not result.errors
99        assert result.data == {"reporters": []}
100
101        ReporterModel.objects.create(first_name="Tara", last_name="West")
102        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
103
104        result = schema.execute(query)
105
106        assert not result.errors
107        assert result.data == {
108            "reporters": [{"firstName": "Tara"}, {"firstName": "Debra"}]
109        }
110
111    def test_override_resolver(self):
112        class Reporter(DjangoObjectType):
113            class Meta:
114                model = ReporterModel
115                fields = ("first_name",)
116
117        class Query(ObjectType):
118            reporters = DjangoListField(Reporter)
119
120            def resolve_reporters(_, info):
121                return ReporterModel.objects.filter(first_name="Tara")
122
123        schema = Schema(query=Query)
124
125        query = """
126            query {
127                reporters {
128                    firstName
129                }
130            }
131        """
132
133        ReporterModel.objects.create(first_name="Tara", last_name="West")
134        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
135
136        result = schema.execute(query)
137
138        assert not result.errors
139        assert result.data == {"reporters": [{"firstName": "Tara"}]}
140
141    def test_nested_list_field(self):
142        class Article(DjangoObjectType):
143            class Meta:
144                model = ArticleModel
145                fields = ("headline",)
146
147        class Reporter(DjangoObjectType):
148            class Meta:
149                model = ReporterModel
150                fields = ("first_name", "articles")
151
152        class Query(ObjectType):
153            reporters = DjangoListField(Reporter)
154
155        schema = Schema(query=Query)
156
157        query = """
158            query {
159                reporters {
160                    firstName
161                    articles {
162                        headline
163                    }
164                }
165            }
166        """
167
168        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
169        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
170
171        ArticleModel.objects.create(
172            headline="Amazing news",
173            reporter=r1,
174            pub_date=datetime.date.today(),
175            pub_date_time=datetime.datetime.now(),
176            editor=r1,
177        )
178        ArticleModel.objects.create(
179            headline="Not so good news",
180            reporter=r1,
181            pub_date=datetime.date.today(),
182            pub_date_time=datetime.datetime.now(),
183            editor=r1,
184        )
185
186        result = schema.execute(query)
187
188        assert not result.errors
189        assert result.data == {
190            "reporters": [
191                {
192                    "firstName": "Tara",
193                    "articles": [
194                        {"headline": "Amazing news"},
195                        {"headline": "Not so good news"},
196                    ],
197                },
198                {"firstName": "Debra", "articles": []},
199            ]
200        }
201
202    def test_override_resolver_nested_list_field(self):
203        class Article(DjangoObjectType):
204            class Meta:
205                model = ArticleModel
206                fields = ("headline",)
207
208        class Reporter(DjangoObjectType):
209            class Meta:
210                model = ReporterModel
211                fields = ("first_name", "articles")
212
213            def resolve_articles(reporter, info):
214                return reporter.articles.filter(headline__contains="Amazing")
215
216        class Query(ObjectType):
217            reporters = DjangoListField(Reporter)
218
219        schema = Schema(query=Query)
220
221        query = """
222            query {
223                reporters {
224                    firstName
225                    articles {
226                        headline
227                    }
228                }
229            }
230        """
231
232        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
233        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
234
235        ArticleModel.objects.create(
236            headline="Amazing news",
237            reporter=r1,
238            pub_date=datetime.date.today(),
239            pub_date_time=datetime.datetime.now(),
240            editor=r1,
241        )
242        ArticleModel.objects.create(
243            headline="Not so good news",
244            reporter=r1,
245            pub_date=datetime.date.today(),
246            pub_date_time=datetime.datetime.now(),
247            editor=r1,
248        )
249
250        result = schema.execute(query)
251
252        assert not result.errors
253        assert result.data == {
254            "reporters": [
255                {"firstName": "Tara", "articles": [{"headline": "Amazing news"}]},
256                {"firstName": "Debra", "articles": []},
257            ]
258        }
259
260    def test_get_queryset_filter(self):
261        class Reporter(DjangoObjectType):
262            class Meta:
263                model = ReporterModel
264                fields = ("first_name", "articles")
265
266            @classmethod
267            def get_queryset(cls, queryset, info):
268                # Only get reporters with at least 1 article
269                return queryset.annotate(article_count=Count("articles")).filter(
270                    article_count__gt=0
271                )
272
273        class Query(ObjectType):
274            reporters = DjangoListField(Reporter)
275
276            def resolve_reporters(_, info):
277                return ReporterModel.objects.all()
278
279        schema = Schema(query=Query)
280
281        query = """
282            query {
283                reporters {
284                    firstName
285                }
286            }
287        """
288
289        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
290        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
291
292        ArticleModel.objects.create(
293            headline="Amazing news",
294            reporter=r1,
295            pub_date=datetime.date.today(),
296            pub_date_time=datetime.datetime.now(),
297            editor=r1,
298        )
299
300        result = schema.execute(query)
301
302        assert not result.errors
303        assert result.data == {"reporters": [{"firstName": "Tara"}]}
304
305    def test_resolve_list(self):
306        """Resolving a plain list should work (and not call get_queryset)"""
307
308        class Reporter(DjangoObjectType):
309            class Meta:
310                model = ReporterModel
311                fields = ("first_name", "articles")
312
313            @classmethod
314            def get_queryset(cls, queryset, info):
315                # Only get reporters with at least 1 article
316                return queryset.annotate(article_count=Count("articles")).filter(
317                    article_count__gt=0
318                )
319
320        class Query(ObjectType):
321            reporters = DjangoListField(Reporter)
322
323            def resolve_reporters(_, info):
324                return [ReporterModel.objects.get(first_name="Debra")]
325
326        schema = Schema(query=Query)
327
328        query = """
329            query {
330                reporters {
331                    firstName
332                }
333            }
334        """
335
336        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
337        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
338
339        ArticleModel.objects.create(
340            headline="Amazing news",
341            reporter=r1,
342            pub_date=datetime.date.today(),
343            pub_date_time=datetime.datetime.now(),
344            editor=r1,
345        )
346
347        result = schema.execute(query)
348
349        assert not result.errors
350        assert result.data == {"reporters": [{"firstName": "Debra"}]}
351
352    def test_get_queryset_foreign_key(self):
353        class Article(DjangoObjectType):
354            class Meta:
355                model = ArticleModel
356                fields = ("headline",)
357
358            @classmethod
359            def get_queryset(cls, queryset, info):
360                # Rose tinted glasses
361                return queryset.exclude(headline__contains="Not so good")
362
363        class Reporter(DjangoObjectType):
364            class Meta:
365                model = ReporterModel
366                fields = ("first_name", "articles")
367
368        class Query(ObjectType):
369            reporters = DjangoListField(Reporter)
370
371        schema = Schema(query=Query)
372
373        query = """
374            query {
375                reporters {
376                    firstName
377                    articles {
378                        headline
379                    }
380                }
381            }
382        """
383
384        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
385        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
386
387        ArticleModel.objects.create(
388            headline="Amazing news",
389            reporter=r1,
390            pub_date=datetime.date.today(),
391            pub_date_time=datetime.datetime.now(),
392            editor=r1,
393        )
394        ArticleModel.objects.create(
395            headline="Not so good news",
396            reporter=r1,
397            pub_date=datetime.date.today(),
398            pub_date_time=datetime.datetime.now(),
399            editor=r1,
400        )
401
402        result = schema.execute(query)
403
404        assert not result.errors
405        assert result.data == {
406            "reporters": [
407                {"firstName": "Tara", "articles": [{"headline": "Amazing news"}]},
408                {"firstName": "Debra", "articles": []},
409            ]
410        }
411