Skip to content

Commit bc6381a

Browse files
authored
Merge pull request #5 from sebsasto/add-merge-fields
Add merge fields
2 parents e9baf60 + 8fbadee commit bc6381a

File tree

4 files changed

+202
-3
lines changed

4 files changed

+202
-3
lines changed

Diff for: 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",)

Diff for: graphene_django/tests/test_query.py

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

Diff for: 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):

Diff for: 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)