mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-13 09:42:32 +03:00
refactor implementation
This commit is contained in:
parent
ff69b07267
commit
b6513f4b1e
|
@ -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
|
|
@ -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',
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue
Block a user