Skip to content

Commit aed2f78

Browse files
author
Sebastian Hernandez
committed
Merge fields used in meta attribute passed on DjangoObjectType
1 parent 4573d3d commit aed2f78

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

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