Skip to content

Commit 5171752

Browse files
authored
Merge pull request #3 from sebsasto/add-merge-fields
Merge fields used in meta attribute passed on DjangoObjectType
2 parents 379954d + aed2f78 commit 5171752

File tree

4 files changed

+201
-3
lines changed

4 files changed

+201
-3
lines changed

graphene_django/tests/models.py

+4
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,9 @@ class Article(models.Model):
115115
def __str__(self): # __unicode__ on Python 2
116116
return self.headline
117117

118+
@property
119+
def headline_with_lang(self):
120+
return "{} - {}".format(self.lang, self.headline)
121+
118122
class Meta:
119123
ordering = ("headline",)

graphene_django/tests/test_query.py

+81-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010

1111
import graphene
1212
from graphene.relay import Node
13+
from graphene.types.utils import yank_fields_from_attrs
1314

1415
from ..compat import IntegerRangeField, MissingType
15-
from ..fields import DjangoConnectionField
16-
from ..types import DjangoObjectType
16+
from ..fields import DjangoConnectionField, DjangoListField
17+
from ..types import DjangoObjectType, DjangoObjectTypeOptions
1718
from ..utils import DJANGO_FILTER_INSTALLED
1819
from .models import Article, CNNReporter, Film, FilmDetails, Reporter
1920

@@ -1593,3 +1594,81 @@ class Query(graphene.ObjectType):
15931594
"allReporters": {"edges": [{"node": {"firstName": "Jane", "lastName": "Roe"}},]}
15941595
}
15951596
assert result.data == expected
1597+
1598+
1599+
def test_should_query_django_objecttype_fields_custom_meta():
1600+
class ArticleTypeOptions(DjangoObjectTypeOptions):
1601+
"""Article Type Options with extra fields"""
1602+
1603+
fields = yank_fields_from_attrs(
1604+
{"headline_with_lang": graphene.String()}, _as=graphene.Field,
1605+
)
1606+
1607+
class ArticleBaseType(DjangoObjectType):
1608+
class Meta:
1609+
abstract = True
1610+
1611+
@classmethod
1612+
def __init_subclass_with_meta__(cls, **options):
1613+
options.setdefault("_meta", ArticleTypeOptions(cls))
1614+
super(ArticleBaseType, cls).__init_subclass_with_meta__(**options)
1615+
1616+
class ArticleCustomType(ArticleBaseType):
1617+
class Meta:
1618+
model = Article
1619+
fields = (
1620+
"headline",
1621+
"lang",
1622+
"headline_with_lang",
1623+
)
1624+
1625+
class Query(graphene.ObjectType):
1626+
all_articles = DjangoListField(ArticleCustomType)
1627+
1628+
r = Reporter.objects.create(
1629+
first_name="John", last_name="Doe", email="[email protected]", a_choice=1
1630+
)
1631+
Article.objects.create(
1632+
headline="Article Node 1",
1633+
pub_date=datetime.date.today(),
1634+
pub_date_time=datetime.datetime.now(),
1635+
reporter=r,
1636+
editor=r,
1637+
lang="es",
1638+
)
1639+
Article.objects.create(
1640+
headline="Article Node 2",
1641+
pub_date=datetime.date.today(),
1642+
pub_date_time=datetime.datetime.now(),
1643+
reporter=r,
1644+
editor=r,
1645+
lang="en",
1646+
)
1647+
1648+
schema = graphene.Schema(query=Query)
1649+
query = """
1650+
query GetAllArticles {
1651+
allArticles {
1652+
headline
1653+
lang
1654+
headlineWithLang
1655+
}
1656+
}
1657+
"""
1658+
result = schema.execute(query)
1659+
assert not result.errors
1660+
expected = {
1661+
"allArticles": [
1662+
{
1663+
"headline": "Article Node 1",
1664+
"lang": "ES",
1665+
"headlineWithLang": "es - Article Node 1",
1666+
},
1667+
{
1668+
"headline": "Article Node 2",
1669+
"lang": "EN",
1670+
"headlineWithLang": "en - Article Node 2",
1671+
},
1672+
]
1673+
}
1674+
assert result.data == expected

graphene_django/tests/test_types.py

+102
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,33 @@ class Meta:
114114
assert isinstance(Article._meta, ArticleTypeOptions)
115115

116116

117+
def test_django_objecttype_with_custom_meta_fields():
118+
class ArticleTypeOptions(DjangoObjectTypeOptions):
119+
"""Article Type Options with extra fields"""
120+
121+
fields = {"headline_with_lang": String()}
122+
123+
class ArticleType(DjangoObjectType):
124+
class Meta:
125+
abstract = True
126+
127+
@classmethod
128+
def __init_subclass_with_meta__(cls, **options):
129+
options.setdefault("_meta", ArticleTypeOptions(cls))
130+
super(ArticleType, cls).__init_subclass_with_meta__(**options)
131+
132+
class Article(ArticleType):
133+
class Meta:
134+
model = ArticleModel
135+
fields = "__all__"
136+
137+
headline_with_lang_field = Article._meta.fields.get("headline_with_lang")
138+
139+
assert isinstance(Article._meta, ArticleTypeOptions)
140+
assert headline_with_lang_field is not None
141+
assert isinstance(headline_with_lang_field, String)
142+
143+
117144
def test_schema_representation():
118145
expected = dedent(
119146
"""\
@@ -278,6 +305,81 @@ class Meta:
278305
assert fields == ["id", "email", "films"]
279306

280307

308+
@with_local_registry
309+
def test_django_objecttype_fields_custom_meta_fields():
310+
class ArticleTypeOptions(DjangoObjectTypeOptions):
311+
"""Article Type Options with extra fields"""
312+
313+
fields = {"headline_with_lang": String()}
314+
315+
class ArticleType(DjangoObjectType):
316+
class Meta:
317+
abstract = True
318+
319+
@classmethod
320+
def __init_subclass_with_meta__(cls, **options):
321+
options.setdefault("_meta", ArticleTypeOptions(cls))
322+
super(ArticleType, cls).__init_subclass_with_meta__(**options)
323+
324+
class Article(ArticleType):
325+
class Meta:
326+
model = ArticleModel
327+
fields = ("editor", "lang", "importance")
328+
329+
fields = list(Article._meta.fields.keys())
330+
assert fields == ["editor", "lang", "importance"]
331+
332+
333+
@with_local_registry
334+
def test_django_objecttype_fields_custom_meta_fields_include():
335+
class ArticleTypeOptions(DjangoObjectTypeOptions):
336+
"""Article Type Options with extra fields"""
337+
338+
fields = {"headline_with_lang": String()}
339+
340+
class ArticleType(DjangoObjectType):
341+
class Meta:
342+
abstract = True
343+
344+
@classmethod
345+
def __init_subclass_with_meta__(cls, **options):
346+
options.setdefault("_meta", ArticleTypeOptions(cls))
347+
super(ArticleType, cls).__init_subclass_with_meta__(**options)
348+
349+
class Article(ArticleType):
350+
class Meta:
351+
model = ArticleModel
352+
fields = ("headline_with_lang", "editor", "lang", "importance")
353+
354+
fields = list(Article._meta.fields.keys())
355+
assert fields == ["headline_with_lang", "editor", "lang", "importance"]
356+
357+
358+
@with_local_registry
359+
def test_django_objecttype_fields_custom_meta_fields_all():
360+
class ArticleTypeOptions(DjangoObjectTypeOptions):
361+
"""Article Type Options with extra fields"""
362+
363+
fields = {"headline_with_lang": String()}
364+
365+
class ArticleType(DjangoObjectType):
366+
class Meta:
367+
abstract = True
368+
369+
@classmethod
370+
def __init_subclass_with_meta__(cls, **options):
371+
options.setdefault("_meta", ArticleTypeOptions(cls))
372+
super(ArticleType, cls).__init_subclass_with_meta__(**options)
373+
374+
class Article(ArticleType):
375+
class Meta:
376+
model = ArticleModel
377+
fields = "__all__"
378+
379+
fields = list(Article._meta.fields.keys())
380+
assert len(fields) == len(ArticleModel._meta.get_fields()) + 1
381+
382+
281383
@with_local_registry
282384
def test_django_objecttype_fields():
283385
class Reporter(DjangoObjectType):

graphene_django/types.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,26 @@ def __init_subclass_with_meta__(
256256

257257
if not _meta:
258258
_meta = DjangoObjectTypeOptions(cls)
259+
elif _meta.fields:
260+
# Exclude previous meta fields that are not in fields or are in exclude
261+
only_fields = fields is not None and fields != ALL_FIELDS
262+
exclude_fields = exclude is not None
263+
if only_fields or exclude_fields:
264+
for name in list(_meta.fields.keys()):
265+
if (only_fields and name not in fields) or (
266+
exclude_fields and name in exclude
267+
):
268+
_meta.fields.pop(name)
259269

260270
_meta.model = model
261271
_meta.registry = registry
262272
_meta.filter_fields = filter_fields
263273
_meta.filterset_class = filterset_class
264-
_meta.fields = django_fields
265274
_meta.connection = connection
275+
if _meta.fields:
276+
_meta.fields.update(django_fields)
277+
else:
278+
_meta.fields = django_fields
266279

267280
super(DjangoObjectType, cls).__init_subclass_with_meta__(
268281
_meta=_meta, interfaces=interfaces, **options

0 commit comments

Comments
 (0)