Merge fields used in meta attribute passed on DjangoObjectType

This commit is contained in:
Sebastian Hernandez 2021-02-22 19:42:25 +01:00
parent 4573d3db53
commit aed2f78bdb
4 changed files with 201 additions and 3 deletions

View File

@ -115,5 +115,9 @@ class Article(models.Model):
def __str__(self): # __unicode__ on Python 2
return self.headline
@property
def headline_with_lang(self):
return "{} - {}".format(self.lang, self.headline)
class Meta:
ordering = ("headline",)

View File

@ -10,10 +10,11 @@ from py.test import raises
import graphene
from graphene.relay import Node
from graphene.types.utils import yank_fields_from_attrs
from ..compat import IntegerRangeField, MissingType
from ..fields import DjangoConnectionField
from ..types import DjangoObjectType
from ..fields import DjangoConnectionField, DjangoListField
from ..types import DjangoObjectType, DjangoObjectTypeOptions
from ..utils import DJANGO_FILTER_INSTALLED
from .models import Article, CNNReporter, Film, FilmDetails, Reporter
@ -1586,3 +1587,81 @@ def test_connection_should_allow_offset_filtering_with_after():
"allReporters": {"edges": [{"node": {"firstName": "Jane", "lastName": "Roe"}},]}
}
assert result.data == expected
def test_should_query_django_objecttype_fields_custom_meta():
class ArticleTypeOptions(DjangoObjectTypeOptions):
"""Article Type Options with extra fields"""
fields = yank_fields_from_attrs(
{"headline_with_lang": graphene.String()}, _as=graphene.Field,
)
class ArticleBaseType(DjangoObjectType):
class Meta:
abstract = True
@classmethod
def __init_subclass_with_meta__(cls, **options):
options.setdefault("_meta", ArticleTypeOptions(cls))
super(ArticleBaseType, cls).__init_subclass_with_meta__(**options)
class ArticleCustomType(ArticleBaseType):
class Meta:
model = Article
fields = (
"headline",
"lang",
"headline_with_lang",
)
class Query(graphene.ObjectType):
all_articles = DjangoListField(ArticleCustomType)
r = Reporter.objects.create(
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
)
Article.objects.create(
headline="Article Node 1",
pub_date=datetime.date.today(),
pub_date_time=datetime.datetime.now(),
reporter=r,
editor=r,
lang="es",
)
Article.objects.create(
headline="Article Node 2",
pub_date=datetime.date.today(),
pub_date_time=datetime.datetime.now(),
reporter=r,
editor=r,
lang="en",
)
schema = graphene.Schema(query=Query)
query = """
query GetAllArticles {
allArticles {
headline
lang
headlineWithLang
}
}
"""
result = schema.execute(query)
assert not result.errors
expected = {
"allArticles": [
{
"headline": "Article Node 1",
"lang": "ES",
"headlineWithLang": "es - Article Node 1",
},
{
"headline": "Article Node 2",
"lang": "EN",
"headlineWithLang": "en - Article Node 2",
},
]
}
assert result.data == expected

View File

@ -114,6 +114,33 @@ def test_django_objecttype_with_custom_meta():
assert isinstance(Article._meta, ArticleTypeOptions)
def test_django_objecttype_with_custom_meta_fields():
class ArticleTypeOptions(DjangoObjectTypeOptions):
"""Article Type Options with extra fields"""
fields = {"headline_with_lang": String()}
class ArticleType(DjangoObjectType):
class Meta:
abstract = True
@classmethod
def __init_subclass_with_meta__(cls, **options):
options.setdefault("_meta", ArticleTypeOptions(cls))
super(ArticleType, cls).__init_subclass_with_meta__(**options)
class Article(ArticleType):
class Meta:
model = ArticleModel
fields = "__all__"
headline_with_lang_field = Article._meta.fields.get("headline_with_lang")
assert isinstance(Article._meta, ArticleTypeOptions)
assert headline_with_lang_field is not None
assert isinstance(headline_with_lang_field, String)
def test_schema_representation():
expected = dedent(
"""\
@ -278,6 +305,81 @@ def test_django_objecttype_only_fields():
assert fields == ["id", "email", "films"]
@with_local_registry
def test_django_objecttype_fields_custom_meta_fields():
class ArticleTypeOptions(DjangoObjectTypeOptions):
"""Article Type Options with extra fields"""
fields = {"headline_with_lang": String()}
class ArticleType(DjangoObjectType):
class Meta:
abstract = True
@classmethod
def __init_subclass_with_meta__(cls, **options):
options.setdefault("_meta", ArticleTypeOptions(cls))
super(ArticleType, cls).__init_subclass_with_meta__(**options)
class Article(ArticleType):
class Meta:
model = ArticleModel
fields = ("editor", "lang", "importance")
fields = list(Article._meta.fields.keys())
assert fields == ["editor", "lang", "importance"]
@with_local_registry
def test_django_objecttype_fields_custom_meta_fields_include():
class ArticleTypeOptions(DjangoObjectTypeOptions):
"""Article Type Options with extra fields"""
fields = {"headline_with_lang": String()}
class ArticleType(DjangoObjectType):
class Meta:
abstract = True
@classmethod
def __init_subclass_with_meta__(cls, **options):
options.setdefault("_meta", ArticleTypeOptions(cls))
super(ArticleType, cls).__init_subclass_with_meta__(**options)
class Article(ArticleType):
class Meta:
model = ArticleModel
fields = ("headline_with_lang", "editor", "lang", "importance")
fields = list(Article._meta.fields.keys())
assert fields == ["headline_with_lang", "editor", "lang", "importance"]
@with_local_registry
def test_django_objecttype_fields_custom_meta_fields_all():
class ArticleTypeOptions(DjangoObjectTypeOptions):
"""Article Type Options with extra fields"""
fields = {"headline_with_lang": String()}
class ArticleType(DjangoObjectType):
class Meta:
abstract = True
@classmethod
def __init_subclass_with_meta__(cls, **options):
options.setdefault("_meta", ArticleTypeOptions(cls))
super(ArticleType, cls).__init_subclass_with_meta__(**options)
class Article(ArticleType):
class Meta:
model = ArticleModel
fields = "__all__"
fields = list(Article._meta.fields.keys())
assert len(fields) == len(ArticleModel._meta.get_fields()) + 1
@with_local_registry
def test_django_objecttype_fields():
class Reporter(DjangoObjectType):

View File

@ -256,13 +256,26 @@ class DjangoObjectType(ObjectType):
if not _meta:
_meta = DjangoObjectTypeOptions(cls)
elif _meta.fields:
# Exclude previous meta fields that are not in fields or are in exclude
only_fields = fields is not None and fields != ALL_FIELDS
exclude_fields = exclude is not None
if only_fields or exclude_fields:
for name in list(_meta.fields.keys()):
if (only_fields and name not in fields) or (
exclude_fields and name in exclude
):
_meta.fields.pop(name)
_meta.model = model
_meta.registry = registry
_meta.filter_fields = filter_fields
_meta.filterset_class = filterset_class
_meta.fields = django_fields
_meta.connection = connection
if _meta.fields:
_meta.fields.update(django_fields)
else:
_meta.fields = django_fields
super(DjangoObjectType, cls).__init_subclass_with_meta__(
_meta=_meta, interfaces=interfaces, **options