mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-14 02:02:20 +03:00
Unify support for models and model form
This commit is contained in:
parent
19fcc3cdf2
commit
9aeee283fa
|
@ -92,7 +92,8 @@ class BaseDjangoFormMutation(ClientIDMutation):
|
||||||
|
|
||||||
class DjangoFormMutationOptions(MutationOptions):
|
class DjangoFormMutationOptions(MutationOptions):
|
||||||
form_class = None
|
form_class = None
|
||||||
|
model = None
|
||||||
|
return_field_name = None
|
||||||
|
|
||||||
class DjangoFormMutation(BaseDjangoFormMutation):
|
class DjangoFormMutation(BaseDjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -100,7 +101,12 @@ class DjangoFormMutation(BaseDjangoFormMutation):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __init_subclass_with_meta__(
|
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:
|
if not form_class:
|
||||||
|
@ -108,19 +114,46 @@ class DjangoFormMutation(BaseDjangoFormMutation):
|
||||||
|
|
||||||
form = form_class()
|
form = form_class()
|
||||||
input_fields = fields_for_form(form, only_fields, exclude_fields)
|
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)
|
input_fields = yank_fields_from_attrs(input_fields, _as=InputField)
|
||||||
|
|
||||||
base_name = cls.__name__
|
base_name = cls.__name__
|
||||||
|
|
||||||
|
_meta = DjangoFormMutationOptions(cls)
|
||||||
|
|
||||||
cls.Errors = create_errors_type(
|
cls.Errors = create_errors_type(
|
||||||
"{}Errors".format(base_name),
|
"{}Errors".format(base_name),
|
||||||
input_fields
|
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)
|
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.form_class = form_class
|
||||||
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
|
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
|
||||||
|
|
||||||
|
@ -128,76 +161,6 @@ class DjangoFormMutation(BaseDjangoFormMutation):
|
||||||
_meta=_meta, input_fields=input_fields, **options
|
_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
|
@classmethod
|
||||||
def perform_mutate(cls, form, info):
|
def perform_mutate(cls, form, info):
|
||||||
obj = form.save()
|
obj = form.save()
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.test import TestCase
|
||||||
from graphene import NonNull, List
|
from graphene import NonNull, List
|
||||||
|
|
||||||
from graphene_django.tests.models import Pet, Film, FilmDetails
|
from graphene_django.tests.models import Pet, Film, FilmDetails
|
||||||
from ..mutation import DjangoFormMutation, DjangoModelFormMutation
|
from ..mutation import DjangoFormMutation
|
||||||
|
|
||||||
|
|
||||||
class MyForm(forms.Form):
|
class MyForm(forms.Form):
|
||||||
|
@ -19,6 +19,12 @@ class PetForm(forms.ModelForm):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class FilmDetailsForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = FilmDetails
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
def test_needs_form_class():
|
def test_needs_form_class():
|
||||||
with pytest.raises(Exception) as exc:
|
with pytest.raises(Exception) as exc:
|
||||||
class MyMutation(DjangoFormMutation):
|
class MyMutation(DjangoFormMutation):
|
||||||
|
@ -44,7 +50,7 @@ def test_has_input_fields():
|
||||||
|
|
||||||
|
|
||||||
def test_default_meta_fields():
|
def test_default_meta_fields():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
|
|
||||||
|
@ -55,7 +61,7 @@ def test_default_meta_fields():
|
||||||
|
|
||||||
|
|
||||||
def test_default_input_meta_fields():
|
def test_default_input_meta_fields():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
|
|
||||||
|
@ -68,7 +74,7 @@ def test_default_input_meta_fields():
|
||||||
|
|
||||||
|
|
||||||
def test_exclude_fields_input_meta_fields():
|
def test_exclude_fields_input_meta_fields():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
exclude_fields = ['id']
|
exclude_fields = ['id']
|
||||||
|
@ -82,30 +88,28 @@ def test_exclude_fields_input_meta_fields():
|
||||||
|
|
||||||
|
|
||||||
def test_return_field_name_is_camelcased():
|
def test_return_field_name_is_camelcased():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class FilmDetailsMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = FilmDetailsForm
|
||||||
model = FilmDetails
|
|
||||||
|
|
||||||
assert PetMutation._meta.model == FilmDetails
|
assert FilmDetailsMutation._meta.model == FilmDetails
|
||||||
assert PetMutation._meta.return_field_name == "filmDetails"
|
assert FilmDetailsMutation._meta.return_field_name == "filmDetails"
|
||||||
|
|
||||||
|
|
||||||
def test_custom_return_field_name():
|
def test_custom_return_field_name_model_form():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class FilmDetailsMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = FilmDetailsForm
|
||||||
model = Film
|
return_field_name = "movie"
|
||||||
return_field_name = "animal"
|
|
||||||
|
|
||||||
assert PetMutation._meta.model == Film
|
assert FilmDetailsMutation._meta.model == FilmDetails
|
||||||
assert PetMutation._meta.return_field_name == "animal"
|
assert FilmDetailsMutation._meta.return_field_name == "movie"
|
||||||
assert "animal" in PetMutation._meta.fields
|
assert "movie" in FilmDetailsMutation._meta.fields
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_model_form_mutation_mutate():
|
def test_model_form_mutation_mutate():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
|
|
||||||
|
@ -121,7 +125,7 @@ def test_model_form_mutation_mutate():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_model_form_mutation_updates_existing():
|
def test_model_form_mutation_updates_existing():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
|
|
||||||
|
@ -136,7 +140,7 @@ def test_model_form_mutation_updates_existing():
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_model_form_mutation_mutate_invalid_form():
|
def test_model_form_mutation_mutate_invalid_form():
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user