mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-13 17:52:19 +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
|
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 mock import patch
|
||||||
|
|
||||||
from graphene import Interface, ObjectType, Schema
|
from graphene import Interface, ObjectType, Schema, Mutation, String
|
||||||
from graphene.relay import Node
|
from graphene.relay import Node
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
from .. import registry
|
from .. import registry
|
||||||
from ..types import DjangoObjectType
|
from ..types import DjangoObjectType, DjangoModelInput
|
||||||
from .models import Article as ArticleModel
|
from .models import Article as ArticleModel
|
||||||
from .models import Reporter as ReporterModel
|
from .models import Reporter as ReporterModel
|
||||||
|
|
||||||
|
@ -163,3 +164,91 @@ def test_django_objecttype_exclude_fields():
|
||||||
|
|
||||||
fields = list(Reporter._meta.fields.keys())
|
fields = list(Reporter._meta.fields.keys())
|
||||||
assert 'email' not in fields
|
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)
|
return cls._meta.model.objects.get(pk=id)
|
||||||
except cls._meta.model.DoesNotExist:
|
except cls._meta.model.DoesNotExist:
|
||||||
return None
|
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