Merge pull request #1 from colanconnon/add-input-types-subclass

add a new subclass and a few tests [WIP]
This commit is contained in:
colan connon 2017-04-27 21:15:03 -04:00 committed by GitHub
commit 854e8720ff
3 changed files with 152 additions and 2 deletions

View File

@ -0,0 +1,7 @@
import collections
from graphene_django import converter, utils
from graphene.types.utils import merge
from graphene.utils.is_base_type import is_base_type

View File

@ -1,10 +1,11 @@
from mock import patch
from graphene import Interface, ObjectType, Schema
from graphene import Interface, ObjectType, Schema, Mutation, String
from graphene.relay import Node
from mock import patch
from .. import registry
from ..types import DjangoObjectType
from ..types import DjangoObjectType, DjangoModelInput
from .models import Article as ArticleModel
from .models import Reporter as ReporterModel
@ -163,3 +164,91 @@ def test_django_objecttype_exclude_fields():
fields = list(Reporter._meta.fields.keys())
assert 'email' not in fields
def test_mutation_execution_with_exclude_fields():
registry.reset_global_registry()
class CreateReporter(Mutation):
first_name = String()
last_name = String()
email = String()
class Input(DjangoModelInput):
class Meta:
model = ReporterModel
exclude_fields = ('id', 'pets', 'a_choice', 'films', 'articles')
def mutate(self, args, context, info):
first_name = args.get('first_name')
last_name = args.get('last_name')
email = args.get('email')
return CreateReporter(first_name=first_name, last_name=last_name, email=email)
class MyMutation(ObjectType):
reporter_input = CreateReporter.Field()
class Query(ObjectType):
a = String()
schema = Schema(query=Query, mutation=MyMutation)
result = schema.execute(''' mutation mymutation {
reporterInput(firstName:"Peter", lastName: "test", email: "test@test.com") {
firstName
lastName
email
}
}
''')
assert not result.errors
assert result.data == {
'reporterInput': {
'firstName': 'Peter',
'lastName': 'test',
'email': "test@test.com"
}
}
def test_mutation_execution():
registry.reset_global_registry()
class ReporterInput(Mutation):
first_name = String()
last_name = String()
class Input(DjangoModelInput):
class Meta:
model = ReporterModel
only_fields = ('first_name', 'last_name')
def mutate(self, args, context, info):
first_name = args.get('first_name')
last_name = args.get('last_name')
return ReporterInput(first_name=first_name, last_name=last_name)
class MyMutation(ObjectType):
reporter_input = ReporterInput.Field()
class Query(ObjectType):
a = String()
schema = Schema(query=Query, mutation=MyMutation)
result = schema.execute(''' mutation mymutation {
reporterInput(firstName:"Peter", lastName: "test") {
firstName
lastName
}
}
''')
assert not result.errors
assert result.data == {
'reporterInput': {
'firstName': 'Peter',
'lastName': 'test',
}
}

View File

@ -122,3 +122,57 @@ class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)):
return cls._meta.model.objects.get(pk=id)
except cls._meta.model.DoesNotExist:
return None
def convert_fields(model, only_fields, exclude_fields):
model_fields = get_model_fields(model=model)
fields = OrderedDict()
for name, field in model_fields:
is_not_in_only = only_fields and name not in only_fields
is_already_created = name in model_fields
is_excluded = name in exclude_fields or is_already_created
is_no_backref = str(name).endswith('+')
if is_not_in_only or is_excluded or is_no_backref:
# We skip this field if we specify only_fields and is not
# in there. Or when we exclude this field in exclude_fields.
# Or when there is no back reference.
continue
converted = convert_django_field_with_choices(field, None)
if not converted:
continue
fields[name] = converted
print(fields)
return fields
class DjangoModelInputMeta(type):
@staticmethod
def __new__(cls, name, bases, attrs):
# We'll get called also for non-user classes like DjangoModelInput. Only
# kick in when called for a sub-class.
if not is_base_type(bases, DjangoModelInputMeta):
return type.__new__(cls, name, bases, attrs)
# Pop Meta info. Must be removed from class, otherwise graphene will
# complain.
meta = attrs.pop('Meta')
if not hasattr(meta, 'exclude_fields'):
setattr(meta, 'exclude_fields', ())
if not hasattr(meta, 'only_fields'):
setattr(meta, 'only_fields', ())
fields = convert_fields(model=meta.model, only_fields=meta.only_fields, exclude_fields=meta.exclude_fields)
attrs = merge(attrs, fields)
return type.__new__(cls, name, bases, attrs)
class DjangoModelInput(six.with_metaclass(DjangoModelInputMeta)):
"""
Derive a mutation's Input class from this and define a meta class with
`model` and `only_fields` members. This will populate the input class
with the converted django members.
"""
pass