From 4453f7a34d0d7299f3505ac487d2a40f421e1abf Mon Sep 17 00:00:00 2001 From: Rustam Ganeyev Date: Sun, 27 Dec 2020 11:08:34 +0000 Subject: [PATCH 1/4] added optional_field to SerializationMutation to forcefully mark some fields as optional --- graphene_django/rest_framework/mutation.py | 10 +++++++++- graphene_django/rest_framework/serializer_converter.py | 9 +++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index 000b21e18..9e2ae12cb 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -18,6 +18,7 @@ class SerializerMutationOptions(MutationOptions): model_class = None model_operations = ["create", "update"] serializer_class = None + optional_fields = () def fields_for_serializer( @@ -27,6 +28,7 @@ def fields_for_serializer( is_input=False, convert_choices_to_enum=True, lookup_field=None, + optional_fields=(), ): fields = OrderedDict() for name, field in serializer.fields.items(): @@ -44,9 +46,13 @@ def fields_for_serializer( if is_not_in_only or is_excluded: continue + is_optional = name in optional_fields fields[name] = convert_serializer_field( - field, is_input=is_input, convert_choices_to_enum=convert_choices_to_enum + field, + is_input=is_input, + convert_choices_to_enum=convert_choices_to_enum, + force_optional=is_optional, ) return fields @@ -70,6 +76,7 @@ def __init_subclass_with_meta__( exclude_fields=(), convert_choices_to_enum=True, _meta=None, + optional_fields=(), **options ): @@ -95,6 +102,7 @@ def __init_subclass_with_meta__( is_input=True, convert_choices_to_enum=convert_choices_to_enum, lookup_field=lookup_field, + optional_fields=optional_fields, ) output_fields = fields_for_serializer( serializer, diff --git a/graphene_django/rest_framework/serializer_converter.py b/graphene_django/rest_framework/serializer_converter.py index 82a113a29..18f34b852 100644 --- a/graphene_django/rest_framework/serializer_converter.py +++ b/graphene_django/rest_framework/serializer_converter.py @@ -19,7 +19,9 @@ def get_graphene_type_from_serializer_field(field): ) -def convert_serializer_field(field, is_input=True, convert_choices_to_enum=True): +def convert_serializer_field( + field, is_input=True, convert_choices_to_enum=True, force_optional=False +): """ Converts a django rest frameworks field to a graphql field and marks the field as required if we are creating an input type @@ -32,7 +34,10 @@ def convert_serializer_field(field, is_input=True, convert_choices_to_enum=True) graphql_type = get_graphene_type_from_serializer_field(field) args = [] - kwargs = {"description": field.help_text, "required": is_input and field.required} + kwargs = { + "description": field.help_text, + "required": is_input and field.required and not force_optional, + } # if it is a tuple or a list it means that we are returning # the graphql type and the child type From 20e505c3abcfa4991bb62d8da96ec2d3b5e4f37b Mon Sep 17 00:00:00 2001 From: Rustam Ganeyev Date: Thu, 31 Dec 2020 11:35:29 +0000 Subject: [PATCH 2/4] added tests --- .../rest_framework/tests/test_mutation.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index ffbc4b570..72adb990d 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -3,7 +3,7 @@ from py.test import raises from rest_framework import serializers -from graphene import Field, ResolveInfo +from graphene import Field, ResolveInfo, NonNull, String from graphene.types.inputobjecttype import InputObjectType from ...types import DjangoObjectType @@ -97,6 +97,26 @@ class Meta: assert "cool_name" in MyMutation.Input._meta.fields assert "created" not in MyMutation.Input._meta.fields +def test_model_serializer_required_fields(): + class MyMutation(SerializerMutation): + class Meta: + serializer_class = MyModelSerializer + + assert "cool_name" in MyMutation.Input._meta.fields + assert MyMutation.Input._meta.fields['cool_name'].type == NonNull(String) + +''' +The same test as previous, but with 'cool_name' in `optional_fields` +''' +def test_model_serializer_optional_fields(): + class MyMutation(SerializerMutation): + class Meta: + serializer_class = MyModelSerializer + optional_fields = ('cool_name') + + assert "cool_name" in MyMutation.Input._meta.fields + assert MyMutation.Input._meta.fields['cool_name'].type == String + def test_write_only_field(): class WriteOnlyFieldModelSerializer(serializers.ModelSerializer): From ca83173af01cb4f35e71782a481790ab82f5d627 Mon Sep 17 00:00:00 2001 From: Rustam Ganeyev Date: Thu, 31 Dec 2020 11:38:32 +0000 Subject: [PATCH 3/4] applied formatting & linting --- .../rest_framework/tests/test_mutation.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index 72adb990d..c8e19ecd5 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -97,25 +97,24 @@ class Meta: assert "cool_name" in MyMutation.Input._meta.fields assert "created" not in MyMutation.Input._meta.fields -def test_model_serializer_required_fields(): + +def test_model_serializer_required_fields(): class MyMutation(SerializerMutation): class Meta: - serializer_class = MyModelSerializer + serializer_class = MyModelSerializer - assert "cool_name" in MyMutation.Input._meta.fields - assert MyMutation.Input._meta.fields['cool_name'].type == NonNull(String) + assert "cool_name" in MyMutation.Input._meta.fields + assert MyMutation.Input._meta.fields["cool_name"].type == NonNull(String) -''' -The same test as previous, but with 'cool_name' in `optional_fields` -''' -def test_model_serializer_optional_fields(): + +def test_model_serializer_optional_fields(): class MyMutation(SerializerMutation): class Meta: serializer_class = MyModelSerializer - optional_fields = ('cool_name') + optional_fields = "cool_name" - assert "cool_name" in MyMutation.Input._meta.fields - assert MyMutation.Input._meta.fields['cool_name'].type == String + assert "cool_name" in MyMutation.Input._meta.fields + assert MyMutation.Input._meta.fields["cool_name"].type == String def test_write_only_field(): From 3daecffe6b7e472f1260a3e690bd507f94e85a8e Mon Sep 17 00:00:00 2001 From: Rustam Ganeyev Date: Fri, 1 Jan 2021 19:46:00 +0000 Subject: [PATCH 4/4] fixed test --- graphene_django/rest_framework/tests/test_mutation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index c8e19ecd5..5c2518d9e 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -111,7 +111,7 @@ def test_model_serializer_optional_fields(): class MyMutation(SerializerMutation): class Meta: serializer_class = MyModelSerializer - optional_fields = "cool_name" + optional_fields = ("cool_name",) assert "cool_name" in MyMutation.Input._meta.fields assert MyMutation.Input._meta.fields["cool_name"].type == String