graphene-django/graphene_django/forms/mutation.py
2017-10-02 09:31:58 -05:00

158 lines
4.6 KiB
Python

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)
field_kwargs = {options.input_field_name: Argument(cls.Input, required=True)}
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)
field_kwargs = {options.input_field_name: Argument(cls.Input, required=True)}
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)