refactor implementation

This commit is contained in:
colan 2017-04-27 21:14:31 -04:00
parent ff69b07267
commit b6513f4b1e
4 changed files with 145 additions and 151 deletions

View File

@ -5,56 +5,3 @@ from graphene.types.utils import merge
from graphene.utils.is_base_type import is_base_type
def convert_fields(model, only_fields, exclude_fields):
model_fields = utils.get_model_fields(model=model)
fields = collections.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
# https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_query_name
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 = converter.convert_django_field(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(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

View File

@ -1,96 +0,0 @@
from mock import patch
from graphene import ObjectType, Schema, Mutation, String
from .. import registry
from ..input_types import DjangoModelInput
from .models import Reporter as ReporterModel
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

@ -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