2017-07-18 18:15:25 +03:00
|
|
|
from functools import partial
|
|
|
|
|
|
|
|
import six
|
|
|
|
import graphene
|
|
|
|
from graphene import Field, Argument
|
|
|
|
from graphene.types.mutation import MutationMeta
|
|
|
|
from graphene.types.objecttype import ObjectTypeMeta
|
|
|
|
from graphene.types.options import Options
|
|
|
|
from graphene.types.utils import get_field_as, merge
|
|
|
|
from graphene.utils.is_base_type import is_base_type
|
|
|
|
from graphene_django.registry import get_global_registry
|
|
|
|
|
|
|
|
from .converter import convert_form_to_input_type
|
|
|
|
from .types import ErrorType
|
|
|
|
|
|
|
|
|
|
|
|
class FormMutationMeta(MutationMeta):
|
|
|
|
def __new__(cls, name, bases, attrs):
|
|
|
|
if not is_base_type(bases, FormMutationMeta):
|
|
|
|
return type.__new__(cls, name, bases, attrs)
|
|
|
|
|
|
|
|
options = Options(
|
|
|
|
attrs.pop('Meta', None),
|
|
|
|
name=name,
|
|
|
|
description=attrs.pop('__doc__', None),
|
|
|
|
form_class=None,
|
|
|
|
input_field_name='input',
|
|
|
|
local_fields=None,
|
|
|
|
only_fields=(),
|
|
|
|
exclude_fields=(),
|
|
|
|
interfaces=(),
|
|
|
|
registry=None
|
|
|
|
)
|
|
|
|
|
|
|
|
if not options.form_class:
|
|
|
|
raise Exception('Missing form_class')
|
|
|
|
|
|
|
|
cls = ObjectTypeMeta.__new__(
|
|
|
|
cls, name, bases, dict(attrs, _meta=options)
|
|
|
|
)
|
|
|
|
|
|
|
|
options.fields = merge(
|
|
|
|
options.interface_fields, options.base_fields, options.local_fields,
|
|
|
|
{'errors': get_field_as(cls.errors, Field)}
|
|
|
|
)
|
|
|
|
|
|
|
|
cls.Input = convert_form_to_input_type(options.form_class)
|
|
|
|
|
2017-07-18 18:31:17 +03:00
|
|
|
field_kwargs = {options.input_field_name: Argument(cls.Input, required=True)}
|
2017-07-18 18:15:25 +03:00
|
|
|
cls.Field = partial(
|
|
|
|
Field,
|
|
|
|
cls,
|
|
|
|
resolver=cls.mutate,
|
|
|
|
**field_kwargs
|
|
|
|
)
|
|
|
|
|
|
|
|
return cls
|
|
|
|
|
|
|
|
|
|
|
|
class BaseFormMutation(graphene.Mutation):
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def mutate(cls, root, args, context, info):
|
|
|
|
form = cls.get_form(root, args, context, info)
|
|
|
|
|
|
|
|
if form.is_valid():
|
|
|
|
return cls.perform_mutate(form, info)
|
|
|
|
else:
|
|
|
|
errors = [
|
|
|
|
ErrorType(field=key, messages=value)
|
|
|
|
for key, value in form.errors.items()
|
|
|
|
]
|
|
|
|
return cls(errors=errors)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def perform_mutate(cls, form, info):
|
|
|
|
form.save()
|
|
|
|
return cls(errors=[])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_form(cls, root, args, context, info):
|
|
|
|
form_data = args.get(cls._meta.input_field_name)
|
|
|
|
kwargs = cls.get_form_kwargs(root, args, context, info)
|
|
|
|
return cls._meta.form_class(data=form_data, **kwargs)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_form_kwargs(cls, root, args, context, info):
|
|
|
|
return {}
|
|
|
|
|
|
|
|
|
|
|
|
class FormMutation(six.with_metaclass(FormMutationMeta, BaseFormMutation)):
|
|
|
|
|
|
|
|
errors = graphene.List(ErrorType)
|
|
|
|
|
|
|
|
|
|
|
|
class ModelFormMutationMeta(MutationMeta):
|
|
|
|
def __new__(cls, name, bases, attrs):
|
|
|
|
if not is_base_type(bases, ModelFormMutationMeta):
|
|
|
|
return type.__new__(cls, name, bases, attrs)
|
|
|
|
|
|
|
|
options = Options(
|
|
|
|
attrs.pop('Meta', None),
|
|
|
|
name=name,
|
|
|
|
description=attrs.pop('__doc__', None),
|
|
|
|
form_class=None,
|
|
|
|
input_field_name='input',
|
|
|
|
return_field_name=None,
|
|
|
|
model=None,
|
|
|
|
local_fields=None,
|
|
|
|
only_fields=(),
|
|
|
|
exclude_fields=(),
|
|
|
|
interfaces=(),
|
|
|
|
registry=None
|
|
|
|
)
|
|
|
|
|
|
|
|
if not options.form_class:
|
|
|
|
raise Exception('Missing form_class')
|
|
|
|
|
|
|
|
cls = ObjectTypeMeta.__new__(
|
|
|
|
cls, name, bases, dict(attrs, _meta=options)
|
|
|
|
)
|
|
|
|
|
|
|
|
options.fields = merge(
|
|
|
|
options.interface_fields, options.base_fields, options.local_fields,
|
|
|
|
{'errors': get_field_as(cls.errors, Field)}
|
|
|
|
)
|
|
|
|
|
|
|
|
cls.Input = convert_form_to_input_type(options.form_class)
|
|
|
|
|
2017-07-18 18:31:17 +03:00
|
|
|
field_kwargs = {options.input_field_name: Argument(cls.Input, required=True)}
|
2017-07-18 18:15:25 +03:00
|
|
|
cls.Field = partial(
|
|
|
|
Field,
|
|
|
|
cls,
|
|
|
|
resolver=cls.mutate,
|
|
|
|
**field_kwargs
|
|
|
|
)
|
|
|
|
|
|
|
|
cls.model = options.model or options.form_class.Meta.model
|
|
|
|
cls.return_field_name = cls._meta.return_field_name or cls.model._meta.model_name
|
|
|
|
|
|
|
|
registry = get_global_registry()
|
|
|
|
model_type = registry.get_type_for_model(cls.model)
|
|
|
|
|
|
|
|
options.fields[cls.return_field_name] = graphene.Field(model_type)
|
|
|
|
|
|
|
|
return cls
|
|
|
|
|
|
|
|
|
|
|
|
class ModelFormMutation(six.with_metaclass(ModelFormMutationMeta, BaseFormMutation)):
|
|
|
|
|
|
|
|
errors = graphene.List(ErrorType)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def perform_mutate(cls, form, info):
|
|
|
|
obj = form.save()
|
|
|
|
kwargs = {cls.return_field_name: obj}
|
|
|
|
return cls(errors=[], **kwargs)
|