Unify support for models and model form

This commit is contained in:
Patrick Arminio 2018-10-28 21:40:19 +00:00
parent 19fcc3cdf2
commit 9aeee283fa
2 changed files with 61 additions and 94 deletions

View File

@ -92,7 +92,8 @@ class BaseDjangoFormMutation(ClientIDMutation):
class DjangoFormMutationOptions(MutationOptions):
form_class = None
model = None
return_field_name = None
class DjangoFormMutation(BaseDjangoFormMutation):
class Meta:
@ -100,7 +101,12 @@ class DjangoFormMutation(BaseDjangoFormMutation):
@classmethod
def __init_subclass_with_meta__(
cls, form_class=None, only_fields=(), exclude_fields=(), **options
cls,
form_class=None,
return_field_name=None,
only_fields=(),
exclude_fields=(),
**options
):
if not form_class:
@ -108,19 +114,46 @@ class DjangoFormMutation(BaseDjangoFormMutation):
form = form_class()
input_fields = fields_for_form(form, only_fields, exclude_fields)
output_fields = fields_for_form(form, only_fields, exclude_fields)
input_fields = yank_fields_from_attrs(input_fields, _as=InputField)
base_name = cls.__name__
_meta = DjangoFormMutationOptions(cls)
cls.Errors = create_errors_type(
"{}Errors".format(base_name),
input_fields
)
# TODO: output
if hasattr(form, '_meta') and hasattr(form._meta, 'model'):
model = form._meta.model
_meta.model = model
registry = get_global_registry()
model_type = registry.get_type_for_model(model)
return_field_name = return_field_name
if "id" not in exclude_fields:
input_fields["id"] = graphene.ID()
if not return_field_name:
model_name = model.__name__
return_field_name = model_name[:1].lower() + model_name[1:]
output_fields = OrderedDict()
output_fields[return_field_name] = graphene.Field(model_type)
else:
# TODO: return field name support
output_fields = fields_for_form(form, only_fields, exclude_fields)
return_field_name = 'TODOFROMForm' if not return_field_name else return_field_name
output_fields['errors'] = graphene.Field(cls.Errors, required=True)
_meta = DjangoFormMutationOptions(cls)
_meta.return_field_name = return_field_name
_meta.form_class = form_class
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
@ -128,76 +161,6 @@ class DjangoFormMutation(BaseDjangoFormMutation):
_meta=_meta, input_fields=input_fields, **options
)
@classmethod
def perform_mutate(cls, form, info):
form.save()
return cls(errors=[])
class DjangoModelDjangoFormMutationOptions(DjangoFormMutationOptions):
model = None
return_field_name = None
class DjangoModelFormMutation(BaseDjangoFormMutation):
class Meta:
abstract = True
@classmethod
def __init_subclass_with_meta__(
cls,
form_class=None,
model=None,
return_field_name=None,
only_fields=(),
exclude_fields=(),
**options
):
if not form_class:
raise Exception("form_class is required for DjangoModelFormMutation")
if not model:
model = form_class._meta.model
if not model:
raise Exception("model is required for DjangoModelFormMutation")
form = form_class()
input_fields = fields_for_form(form, only_fields, exclude_fields)
if "id" not in exclude_fields:
input_fields["id"] = graphene.ID()
registry = get_global_registry()
model_type = registry.get_type_for_model(model)
return_field_name = return_field_name
if not return_field_name:
model_name = model.__name__
return_field_name = model_name[:1].lower() + model_name[1:]
output_fields = OrderedDict()
output_fields[return_field_name] = graphene.Field(model_type)
input_fields = yank_fields_from_attrs(input_fields, _as=InputField)
base_name = cls.__name__
cls.Errors = create_errors_type(
"{}Errors".format(base_name),
input_fields
)
output_fields['errors'] = graphene.Field(cls.Errors, required=True)
_meta = DjangoModelDjangoFormMutationOptions(cls)
_meta.form_class = form_class
_meta.model = model
_meta.return_field_name = return_field_name
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
super(DjangoModelFormMutation, cls).__init_subclass_with_meta__(
_meta=_meta, input_fields=input_fields, **options
)
@classmethod
def perform_mutate(cls, form, info):
obj = form.save()

View File

@ -6,7 +6,7 @@ from django.test import TestCase
from graphene import NonNull, List
from graphene_django.tests.models import Pet, Film, FilmDetails
from ..mutation import DjangoFormMutation, DjangoModelFormMutation
from ..mutation import DjangoFormMutation
class MyForm(forms.Form):
@ -19,6 +19,12 @@ class PetForm(forms.ModelForm):
fields = '__all__'
class FilmDetailsForm(forms.ModelForm):
class Meta:
model = FilmDetails
fields = '__all__'
def test_needs_form_class():
with pytest.raises(Exception) as exc:
class MyMutation(DjangoFormMutation):
@ -44,7 +50,7 @@ def test_has_input_fields():
def test_default_meta_fields():
class PetMutation(DjangoModelFormMutation):
class PetMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
@ -55,7 +61,7 @@ def test_default_meta_fields():
def test_default_input_meta_fields():
class PetMutation(DjangoModelFormMutation):
class PetMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
@ -68,7 +74,7 @@ def test_default_input_meta_fields():
def test_exclude_fields_input_meta_fields():
class PetMutation(DjangoModelFormMutation):
class PetMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
exclude_fields = ['id']
@ -82,30 +88,28 @@ def test_exclude_fields_input_meta_fields():
def test_return_field_name_is_camelcased():
class PetMutation(DjangoModelFormMutation):
class FilmDetailsMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
model = FilmDetails
form_class = FilmDetailsForm
assert PetMutation._meta.model == FilmDetails
assert PetMutation._meta.return_field_name == "filmDetails"
assert FilmDetailsMutation._meta.model == FilmDetails
assert FilmDetailsMutation._meta.return_field_name == "filmDetails"
def test_custom_return_field_name():
class PetMutation(DjangoModelFormMutation):
def test_custom_return_field_name_model_form():
class FilmDetailsMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
model = Film
return_field_name = "animal"
form_class = FilmDetailsForm
return_field_name = "movie"
assert PetMutation._meta.model == Film
assert PetMutation._meta.return_field_name == "animal"
assert "animal" in PetMutation._meta.fields
assert FilmDetailsMutation._meta.model == FilmDetails
assert FilmDetailsMutation._meta.return_field_name == "movie"
assert "movie" in FilmDetailsMutation._meta.fields
@pytest.mark.django_db
def test_model_form_mutation_mutate():
class PetMutation(DjangoModelFormMutation):
class PetMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
@ -121,7 +125,7 @@ def test_model_form_mutation_mutate():
@pytest.mark.django_db
def test_model_form_mutation_updates_existing():
class PetMutation(DjangoModelFormMutation):
class PetMutation(DjangoFormMutation):
class Meta:
form_class = PetForm
@ -136,7 +140,7 @@ def test_model_form_mutation_updates_existing():
@pytest.mark.django_db
def test_model_form_mutation_mutate_invalid_form():
class PetMutation(DjangoModelFormMutation):
class PetMutation(DjangoFormMutation):
class Meta:
form_class = PetForm