From c416a2b0f521b0c8b491bf610816bc10bfff5e67 Mon Sep 17 00:00:00 2001 From: Noxx Date: Wed, 20 Dec 2023 10:55:15 +0100 Subject: [PATCH] Provide setting to enable/disable converting choices to enums globally (#1477) Co-authored-by: Firas Kafri <3097061+firaskafri@users.noreply.github.com> Co-authored-by: Kien Dang --- docs/settings.rst | 9 +++ graphene_django/converter.py | 6 +- graphene_django/settings.py | 2 + graphene_django/tests/test_types.py | 116 ++++++++++++++++++++++++++++ graphene_django/types.py | 6 +- 5 files changed, 135 insertions(+), 4 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 79c52e2..521e434 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -142,6 +142,15 @@ Default: ``False`` # ] +``DJANGO_CHOICE_FIELD_ENUM_CONVERT`` +-------------------------------------- + +When set to ``True`` Django choice fields are automatically converted into Enum types. + +Can be disabled globally by setting it to ``False``. + +Default: ``True`` + ``DJANGO_CHOICE_FIELD_ENUM_V2_NAMING`` -------------------------------------- diff --git a/graphene_django/converter.py b/graphene_django/converter.py index f4775e8..121c1de 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -133,13 +133,17 @@ def convert_choice_field_to_enum(field, name=None): def convert_django_field_with_choices( - field, registry=None, convert_choices_to_enum=True + field, registry=None, convert_choices_to_enum=None ): if registry is not None: converted = registry.get_converted_field(field) if converted: return converted choices = getattr(field, "choices", None) + if convert_choices_to_enum is None: + convert_choices_to_enum = bool( + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CONVERT + ) if choices and convert_choices_to_enum: EnumCls = convert_choice_field_to_enum(field) required = not (field.blank or field.null) diff --git a/graphene_django/settings.py b/graphene_django/settings.py index f7e3ee7..da33700 100644 --- a/graphene_django/settings.py +++ b/graphene_django/settings.py @@ -30,6 +30,8 @@ DEFAULTS = { # Max items returned in ConnectionFields / FilterConnectionFields "RELAY_CONNECTION_MAX_LIMIT": 100, "CAMELCASE_ERRORS": True, + # Automatically convert Choice fields of Django into Enum fields + "DJANGO_CHOICE_FIELD_ENUM_CONVERT": True, # Set to True to enable v2 naming convention for choice field Enum's "DJANGO_CHOICE_FIELD_ENUM_V2_NAMING": False, "DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME": None, diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 34828db..5c36bb9 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -661,6 +661,122 @@ class TestDjangoObjectType: }""" ) + def test_django_objecttype_convert_choices_global_false( + self, graphene_settings, PetModel + ): + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CONVERT = False + + class Pet(DjangoObjectType): + class Meta: + model = PetModel + fields = "__all__" + + class Query(ObjectType): + pet = Field(Pet) + + schema = Schema(query=Query) + + assert str(schema) == dedent( + """\ + type Query { + pet: Pet + } + + type Pet { + id: ID! + kind: String! + cuteness: Int! + }""" + ) + + def test_django_objecttype_convert_choices_true_global_false( + self, graphene_settings, PetModel + ): + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CONVERT = False + + class Pet(DjangoObjectType): + class Meta: + model = PetModel + fields = "__all__" + convert_choices_to_enum = True + + class Query(ObjectType): + pet = Field(Pet) + + schema = Schema(query=Query) + + assert str(schema) == dedent( + """\ + type Query { + pet: Pet + } + + type Pet { + id: ID! + kind: TestsPetModelKindChoices! + cuteness: TestsPetModelCutenessChoices! + } + + \"""An enumeration.\""" + enum TestsPetModelKindChoices { + \"""Cat\""" + CAT + + \"""Dog\""" + DOG + } + + \"""An enumeration.\""" + enum TestsPetModelCutenessChoices { + \"""Kind of cute\""" + A_1 + + \"""Pretty cute\""" + A_2 + + \"""OMG SO CUTE!!!\""" + A_3 + }""" + ) + + def test_django_objecttype_convert_choices_enum_list_global_false( + self, graphene_settings, PetModel + ): + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CONVERT = False + + class Pet(DjangoObjectType): + class Meta: + model = PetModel + convert_choices_to_enum = ["kind"] + fields = "__all__" + + class Query(ObjectType): + pet = Field(Pet) + + schema = Schema(query=Query) + + assert str(schema) == dedent( + """\ + type Query { + pet: Pet + } + + type Pet { + id: ID! + kind: TestsPetModelKindChoices! + cuteness: Int! + } + + \"""An enumeration.\""" + enum TestsPetModelKindChoices { + \"""Cat\""" + CAT + + \"""Dog\""" + DOG + }""" + ) + @with_local_registry def test_django_objecttype_name_connection_propagation(): diff --git a/graphene_django/types.py b/graphene_django/types.py index 02b7693..e310fe4 100644 --- a/graphene_django/types.py +++ b/graphene_django/types.py @@ -23,7 +23,7 @@ ALL_FIELDS = "__all__" def construct_fields( - model, registry, only_fields, exclude_fields, convert_choices_to_enum + model, registry, only_fields, exclude_fields, convert_choices_to_enum=None ): _model_fields = get_model_fields(model) @@ -47,7 +47,7 @@ def construct_fields( continue _convert_choices_to_enum = convert_choices_to_enum - if not isinstance(_convert_choices_to_enum, bool): + if isinstance(_convert_choices_to_enum, list): # then `convert_choices_to_enum` is a list of field names to convert if name in _convert_choices_to_enum: _convert_choices_to_enum = True @@ -146,7 +146,7 @@ class DjangoObjectType(ObjectType): connection_class=None, use_connection=None, interfaces=(), - convert_choices_to_enum=True, + convert_choices_to_enum=None, _meta=None, **options, ):