2017-05-31 01:30:03 +03:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
import graphene
|
2017-07-25 09:42:40 +03:00
|
|
|
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)
|
2017-08-31 19:07:05 +03:00
|
|
|
_meta.serializer_class = serializer_class
|
2017-07-25 08:27:50 +03:00
|
|
|
_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-28 19:43:27 +03:00
|
|
|
def mutate_and_get_payload(cls, root, info, **input):
|
|
|
|
serializer = cls._meta.serializer_class(data=input)
|
2017-05-31 01:30:03 +03:00
|
|
|
|
|
|
|
if serializer.is_valid():
|
2017-07-28 19:43:27 +03:00
|
|
|
return cls.perform_mutate(serializer, 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-28 19:43:27 +03:00
|
|
|
def perform_mutate(cls, serializer, info):
|
2017-06-26 20:03:01 +03:00
|
|
|
obj = serializer.save()
|
2017-08-31 20:15:18 +03:00
|
|
|
return cls(errors=None, **obj)
|