graphene-django/graphene_django/rest_framework/mutation.py

89 lines
2.7 KiB
Python
Raw Normal View History

2017-05-31 01:30:03 +03:00
from collections import OrderedDict
import graphene
2017-07-25 09:42:40 +03:00
from graphene import annotate, Context, ResolveInfo
from graphene.types import Field, InputField
from graphene.types.mutation import MutationOptions
from graphene.relay.mutation import ClientIDMutation
2017-05-31 01:30:03 +03:00
from graphene.types.objecttype import (
yank_fields_from_attrs
)
from .serializer_converter import (
convert_serializer_field
)
from .types import ErrorType
2017-07-25 08:27:50 +03:00
class SerializerMutationOptions(MutationOptions):
serializer_class = None
2017-05-31 01:30:03 +03:00
2017-07-25 09:42:40 +03:00
def fields_for_serializer(serializer, only_fields, exclude_fields, is_input=False):
2017-07-25 08:27:50 +03:00
fields = OrderedDict()
for name, field in serializer.fields.items():
is_not_in_only = only_fields and name not in only_fields
is_excluded = (
2017-07-25 09:42:40 +03:00
name in exclude_fields # or
2017-07-25 08:27:50 +03:00
# name in already_created_fields
2017-05-31 01:30:03 +03:00
)
2017-07-25 08:27:50 +03:00
if is_not_in_only or is_excluded:
continue
2017-05-31 01:30:03 +03:00
2017-07-25 09:42:40 +03:00
fields[name] = convert_serializer_field(field, is_input=is_input)
2017-07-25 08:27:50 +03:00
return fields
2017-05-31 01:30:03 +03:00
2017-07-25 09:42:40 +03:00
class SerializerMutation(ClientIDMutation):
class Meta:
abstract = True
2017-07-25 08:27:50 +03:00
errors = graphene.List(
ErrorType,
description='May contain more than one error for same field.'
)
2017-05-31 01:30:03 +03:00
2017-07-25 08:27:50 +03:00
@classmethod
2017-07-25 09:42:40 +03:00
def __init_subclass_with_meta__(cls, serializer_class=None,
only_fields=(), exclude_fields=(), **options):
2017-05-31 01:30:03 +03:00
2017-07-25 08:27:50 +03:00
if not serializer_class:
raise Exception('serializer_class is required for the SerializerMutation')
2017-05-31 01:30:03 +03:00
2017-07-25 08:27:50 +03:00
serializer = serializer_class()
2017-07-25 09:42:40 +03:00
input_fields = fields_for_serializer(serializer, only_fields, exclude_fields, is_input=True)
output_fields = fields_for_serializer(serializer, only_fields, exclude_fields, is_input=False)
2017-05-31 01:30:03 +03:00
2017-07-25 08:27:50 +03:00
_meta = SerializerMutationOptions(cls)
_meta.fields = yank_fields_from_attrs(
2017-07-25 09:42:40 +03:00
output_fields,
2017-07-25 08:27:50 +03:00
_as=Field,
)
2017-05-31 01:30:03 +03:00
2017-07-25 09:42:40 +03:00
input_fields = yank_fields_from_attrs(
input_fields,
2017-07-25 08:27:50 +03:00
_as=InputField,
)
2017-07-25 09:42:40 +03:00
super(SerializerMutation, cls).__init_subclass_with_meta__(_meta=_meta, input_fields=input_fields, **options)
2017-05-31 01:30:03 +03:00
@classmethod
2017-07-25 09:42:40 +03:00
@annotate(context=Context, info=ResolveInfo)
def mutate_and_get_payload(cls, root, input, context, info):
2017-05-31 01:30:03 +03:00
serializer = cls._meta.serializer_class(data=dict(input))
if serializer.is_valid():
2017-07-25 09:42:40 +03:00
return cls.perform_mutate(serializer, context, info)
2017-05-31 01:30:03 +03:00
else:
errors = [
ErrorType(field=key, messages=value)
for key, value in serializer.errors.items()
]
return cls(errors=errors)
@classmethod
2017-07-25 09:42:40 +03:00
def perform_mutate(cls, serializer, context, info):
2017-06-26 20:03:01 +03:00
obj = serializer.save()
2017-07-25 09:42:40 +03:00
return cls(**obj)