From edbb14e656d7e9ee17647d4f18ea81fc3c4c2f8e Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sat, 11 Jan 2020 17:07:54 +0000 Subject: [PATCH 01/12] Add new setting to create unique enum names --- graphene_django/converter.py | 17 +++++++++++-- graphene_django/settings.py | 2 ++ graphene_django/tests/test_types.py | 37 +++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 8b93d175c..fea0b42da 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -22,6 +22,7 @@ from graphene.utils.str_converters import to_camel_case, to_const from graphql import assert_valid_name +from .settings import graphene_settings from .compat import ArrayField, HStoreField, JSONField, RangeField from .fields import DjangoListField, DjangoConnectionField from .utils import import_single_dispatch @@ -68,6 +69,19 @@ def description(self): return Enum(name, list(named_choices), type=EnumWithDescriptionsType) +def generate_enum_name(django_model, field): + meta = django_model._meta + if graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME is True: + name = "DjangoModel{app_label}{object_name}{field_name}Choices".format( + app_label=to_camel_case(meta.app_label).capitalize(), + object_name=meta.object_name, + field_name=to_camel_case(field.name).capitalize(), + ) + else: + name = to_camel_case("{}_{}".format(meta.object_name, field.name)) + return name + + def convert_django_field_with_choices( field, registry=None, convert_choices_to_enum=True ): @@ -77,8 +91,7 @@ def convert_django_field_with_choices( return converted choices = getattr(field, "choices", None) if choices and convert_choices_to_enum: - meta = field.model._meta - name = to_camel_case("{}_{}".format(meta.object_name, field.name)) + name = generate_enum_name(field.model, field) enum = convert_choices_to_named_enum_with_descriptions(name, choices) required = not (field.blank or field.null) converted = enum(description=field.help_text, required=required) diff --git a/graphene_django/settings.py b/graphene_django/settings.py index 9a5e8a906..5582b03ef 100644 --- a/graphene_django/settings.py +++ b/graphene_django/settings.py @@ -36,6 +36,8 @@ # Max items returned in ConnectionFields / FilterConnectionFields "RELAY_CONNECTION_MAX_LIMIT": 100, "CAMELCASE_ERRORS": False, + # Set to True to enable unique naming for choice field Enum's + "CHOICES_TO_ENUM_UNIQUE_TYPE_NAME": False, } if settings.DEBUG: diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index c32f46cef..7a37086d4 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -9,6 +9,7 @@ from graphene.relay import Node from .. import registry +from ..settings import graphene_settings from ..types import DjangoObjectType, DjangoObjectTypeOptions from .models import Article as ArticleModel from .models import Reporter as ReporterModel @@ -492,3 +493,39 @@ class Query(ObjectType): } """ ) + + def test_django_objecttype_convert_choices_enum_naming_collisions(self, PetModel): + graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = True + + class PetModelKind(DjangoObjectType): + class Meta: + model = PetModel + fields = ["id", "kind"] + + class Query(ObjectType): + pet = Field(PetModelKind) + + schema = Schema(query=Query) + + assert str(schema) == dedent( + """\ + schema { + query: Query + } + + enum DjangoModelTestsPetModelKindChoices { + CAT + DOG + } + + type PetModelKind { + id: ID! + kind: DjangoModelTestsPetModelKindChoices! + } + + type Query { + pet: PetModelKind + } + """ + ) + graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = False From b4b64fd6f476e81b908f110345b75f5952bf94e1 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sat, 11 Jan 2020 17:17:51 +0000 Subject: [PATCH 02/12] Add specific tests for name generation --- graphene_django/converter.py | 13 +++++------ graphene_django/tests/test_converter.py | 30 ++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index fea0b42da..f3b0fd2d6 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -69,16 +69,15 @@ def description(self): return Enum(name, list(named_choices), type=EnumWithDescriptionsType) -def generate_enum_name(django_model, field): - meta = django_model._meta +def generate_enum_name(django_model_meta, field): if graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME is True: name = "DjangoModel{app_label}{object_name}{field_name}Choices".format( - app_label=to_camel_case(meta.app_label).capitalize(), - object_name=meta.object_name, - field_name=to_camel_case(field.name).capitalize(), + app_label=to_camel_case(django_model_meta.app_label.title()), + object_name=django_model_meta.object_name, + field_name=to_camel_case(field.name.title()), ) else: - name = to_camel_case("{}_{}".format(meta.object_name, field.name)) + name = to_camel_case("{}_{}".format(django_model_meta.object_name, field.name)) return name @@ -91,7 +90,7 @@ def convert_django_field_with_choices( return converted choices = getattr(field, "choices", None) if choices and convert_choices_to_enum: - name = generate_enum_name(field.model, field) + name = generate_enum_name(field.model._meta, field) enum = convert_choices_to_named_enum_with_descriptions(name, choices) required = not (field.blank or field.null) converted = enum(description=field.help_text, required=required) diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index 3790c4a7b..f34f19841 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -1,4 +1,5 @@ import pytest +from collections import namedtuple from django.db import models from django.utils.translation import ugettext_lazy as _ from graphene import NonNull @@ -10,9 +11,14 @@ from graphene.types.json import JSONString from ..compat import JSONField, ArrayField, HStoreField, RangeField, MissingType -from ..converter import convert_django_field, convert_django_field_with_choices +from ..converter import ( + convert_django_field, + convert_django_field_with_choices, + generate_enum_name, +) from ..registry import Registry from ..types import DjangoObjectType +from ..settings import graphene_settings from .models import Article, Film, FilmDetails, Reporter @@ -325,3 +331,25 @@ def test_should_postgres_range_convert_list(): assert isinstance(field.type, graphene.NonNull) assert isinstance(field.type.of_type, graphene.List) assert field.type.of_type.of_type == graphene.Int + + +def test_generate_enum_name(): + MockDjangoModelMeta = namedtuple("DjangoMeta", ["app_label", "object_name"]) + graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = True + + # Simple case + field = graphene.Field(graphene.String, name="type") + model_meta = MockDjangoModelMeta(app_label="users", object_name="User") + assert generate_enum_name(model_meta, field) == "DjangoModelUsersUserTypeChoices" + + # More complicated multiple work case + field = graphene.Field(graphene.String, name="fizz_buzz") + model_meta = MockDjangoModelMeta( + app_label="some_long_app_name", object_name="SomeObject" + ) + assert ( + generate_enum_name(model_meta, field) + == "DjangoModelSomeLongAppNameSomeObjectFizzBuzzChoices" + ) + + graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = False From 8c20e183ad2d880aaba5b35ce9d6d1374e575d12 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 22 Jan 2020 10:00:27 +0000 Subject: [PATCH 03/12] Add schema test --- graphene_django/converter.py | 10 +++++-- graphene_django/tests/test_types.py | 41 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index f3b0fd2d6..e3890ac08 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -81,6 +81,13 @@ def generate_enum_name(django_model_meta, field): return name +def convert_choice_field_to_enum(field, name=None): + if name is None: + name = generate_enum_name(field.model._meta, field) + choices = field.choices + return convert_choices_to_named_enum_with_descriptions(name, choices) + + def convert_django_field_with_choices( field, registry=None, convert_choices_to_enum=True ): @@ -90,8 +97,7 @@ def convert_django_field_with_choices( return converted choices = getattr(field, "choices", None) if choices and convert_choices_to_enum: - name = generate_enum_name(field.model._meta, field) - enum = convert_choices_to_named_enum_with_descriptions(name, choices) + enum = convert_choice_field_to_enum(field) required = not (field.blank or field.null) converted = enum(description=field.help_text, required=required) else: diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 7a37086d4..712626de0 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -11,6 +11,7 @@ from .. import registry from ..settings import graphene_settings from ..types import DjangoObjectType, DjangoObjectTypeOptions +from ..converter import convert_choice_field_to_enum from .models import Article as ArticleModel from .models import Reporter as ReporterModel @@ -529,3 +530,43 @@ class Query(ObjectType): """ ) graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = False + + def test_django_objecttype_choices_override_enum(self, PetModel): + def convert_choice(model, field_name, **kwargs): + return convert_choice_field_to_enum( + model._meta.get_field(field_name), **kwargs + ) + + class PetModelKind(DjangoObjectType): + kind = Field(convert_choice(PetModel, "kind", name="CustomEnumName")) + + class Meta: + model = PetModel + fields = ["id", "kind"] + + class Query(ObjectType): + pet = Field(PetModelKind) + + schema = Schema(query=Query) + + assert str(schema) == dedent( + """\ + schema { + query: Query + } + + enum DjangoModelTestsPetModelKindChoices { + CAT + DOG + } + + type PetModelKind { + id: ID! + kind: DjangoModelTestsPetModelKindChoices! + } + + type Query { + pet: PetModelKind + } + """ + ) From fdaa0bf2badac61b25db65e8af5a715192cbd0d0 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 22 Jan 2020 10:02:59 +0000 Subject: [PATCH 04/12] Rename settings field --- graphene_django/converter.py | 2 +- graphene_django/settings.py | 4 ++-- graphene_django/tests/test_converter.py | 4 ++-- graphene_django/tests/test_types.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index e3890ac08..a586e8b15 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -70,7 +70,7 @@ def description(self): def generate_enum_name(django_model_meta, field): - if graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME is True: + if graphene_settings.CHOICES_TO_ENUM_V3_NAMING is True: name = "DjangoModel{app_label}{object_name}{field_name}Choices".format( app_label=to_camel_case(django_model_meta.app_label.title()), object_name=django_model_meta.object_name, diff --git a/graphene_django/settings.py b/graphene_django/settings.py index 5582b03ef..1b579dd2c 100644 --- a/graphene_django/settings.py +++ b/graphene_django/settings.py @@ -36,8 +36,8 @@ # Max items returned in ConnectionFields / FilterConnectionFields "RELAY_CONNECTION_MAX_LIMIT": 100, "CAMELCASE_ERRORS": False, - # Set to True to enable unique naming for choice field Enum's - "CHOICES_TO_ENUM_UNIQUE_TYPE_NAME": False, + # Set to True to enable v3 naming convention for choice field Enum's + "CHOICES_TO_ENUM_V3_NAMING": False, } if settings.DEBUG: diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index f34f19841..bbda2e316 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -335,7 +335,7 @@ def test_should_postgres_range_convert_list(): def test_generate_enum_name(): MockDjangoModelMeta = namedtuple("DjangoMeta", ["app_label", "object_name"]) - graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = True + graphene_settings.CHOICES_TO_ENUM_V3_NAMING = True # Simple case field = graphene.Field(graphene.String, name="type") @@ -352,4 +352,4 @@ def test_generate_enum_name(): == "DjangoModelSomeLongAppNameSomeObjectFizzBuzzChoices" ) - graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = False + graphene_settings.CHOICES_TO_ENUM_V3_NAMING = False diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 712626de0..800863b2f 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -496,7 +496,7 @@ class Query(ObjectType): ) def test_django_objecttype_convert_choices_enum_naming_collisions(self, PetModel): - graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = True + graphene_settings.CHOICES_TO_ENUM_V3_NAMING = True class PetModelKind(DjangoObjectType): class Meta: @@ -529,7 +529,7 @@ class Query(ObjectType): } """ ) - graphene_settings.CHOICES_TO_ENUM_UNIQUE_TYPE_NAME = False + graphene_settings.CHOICES_TO_ENUM_V3_NAMING = False def test_django_objecttype_choices_override_enum(self, PetModel): def convert_choice(model, field_name, **kwargs): From f9252e3c4e70537514de92f4cfe6703a406c91fc Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 22 Jan 2020 10:28:35 +0000 Subject: [PATCH 05/12] Rename setting --- graphene_django/converter.py | 2 +- graphene_django/settings.py | 2 +- graphene_django/tests/test_converter.py | 4 ++-- graphene_django/tests/test_types.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index a586e8b15..0492ce23a 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -70,7 +70,7 @@ def description(self): def generate_enum_name(django_model_meta, field): - if graphene_settings.CHOICES_TO_ENUM_V3_NAMING is True: + if graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING is True: name = "DjangoModel{app_label}{object_name}{field_name}Choices".format( app_label=to_camel_case(django_model_meta.app_label.title()), object_name=django_model_meta.object_name, diff --git a/graphene_django/settings.py b/graphene_django/settings.py index 1b579dd2c..75b5fa3ce 100644 --- a/graphene_django/settings.py +++ b/graphene_django/settings.py @@ -37,7 +37,7 @@ "RELAY_CONNECTION_MAX_LIMIT": 100, "CAMELCASE_ERRORS": False, # Set to True to enable v3 naming convention for choice field Enum's - "CHOICES_TO_ENUM_V3_NAMING": False, + "DJANGO_CHOICE_FIELD_ENUM_V3_NAMING": False, } if settings.DEBUG: diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index bbda2e316..1eb1e3ffa 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -335,7 +335,7 @@ def test_should_postgres_range_convert_list(): def test_generate_enum_name(): MockDjangoModelMeta = namedtuple("DjangoMeta", ["app_label", "object_name"]) - graphene_settings.CHOICES_TO_ENUM_V3_NAMING = True + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = True # Simple case field = graphene.Field(graphene.String, name="type") @@ -352,4 +352,4 @@ def test_generate_enum_name(): == "DjangoModelSomeLongAppNameSomeObjectFizzBuzzChoices" ) - graphene_settings.CHOICES_TO_ENUM_V3_NAMING = False + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = False diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 800863b2f..368ae8327 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -496,7 +496,7 @@ class Query(ObjectType): ) def test_django_objecttype_convert_choices_enum_naming_collisions(self, PetModel): - graphene_settings.CHOICES_TO_ENUM_V3_NAMING = True + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = True class PetModelKind(DjangoObjectType): class Meta: @@ -529,7 +529,7 @@ class Query(ObjectType): } """ ) - graphene_settings.CHOICES_TO_ENUM_V3_NAMING = False + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = False def test_django_objecttype_choices_override_enum(self, PetModel): def convert_choice(model, field_name, **kwargs): From ecdbae3c8ac7d863ded622fd347a5a91f75f0048 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 22 Jan 2020 10:31:27 +0000 Subject: [PATCH 06/12] Add custom function setting --- graphene_django/converter.py | 6 +++++- graphene_django/settings.py | 1 + graphene_django/tests/test_types.py | 18 +++++++++--------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 0492ce23a..a986d7ac8 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -70,7 +70,11 @@ def description(self): def generate_enum_name(django_model_meta, field): - if graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING is True: + if graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME and callable( + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME + ): + name = graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME(field) + elif graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING is True: name = "DjangoModel{app_label}{object_name}{field_name}Choices".format( app_label=to_camel_case(django_model_meta.app_label.title()), object_name=django_model_meta.object_name, diff --git a/graphene_django/settings.py b/graphene_django/settings.py index 75b5fa3ce..666ad8a14 100644 --- a/graphene_django/settings.py +++ b/graphene_django/settings.py @@ -38,6 +38,7 @@ "CAMELCASE_ERRORS": False, # Set to True to enable v3 naming convention for choice field Enum's "DJANGO_CHOICE_FIELD_ENUM_V3_NAMING": False, + "DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME": None, } if settings.DEBUG: diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 368ae8327..a3261df79 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -514,14 +514,14 @@ class Query(ObjectType): query: Query } - enum DjangoModelTestsPetModelKindChoices { + enum CustomEnumKind { CAT DOG } type PetModelKind { id: ID! - kind: DjangoModelTestsPetModelKindChoices! + kind: CustomEnumKind! } type Query { @@ -531,15 +531,13 @@ class Query(ObjectType): ) graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = False - def test_django_objecttype_choices_override_enum(self, PetModel): - def convert_choice(model, field_name, **kwargs): - return convert_choice_field_to_enum( - model._meta.get_field(field_name), **kwargs - ) + def test_django_objecttype_choices_custom_enum_name(self, PetModel): + def custom_name(field): + return f"CustomEnum{field.name.title()}" - class PetModelKind(DjangoObjectType): - kind = Field(convert_choice(PetModel, "kind", name="CustomEnumName")) + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME = custom_name + class PetModelKind(DjangoObjectType): class Meta: model = PetModel fields = ["id", "kind"] @@ -570,3 +568,5 @@ class Query(ObjectType): } """ ) + + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME = None From cad37176a683a7e82807960aa253836342bf93d5 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 22 Jan 2020 10:49:40 +0000 Subject: [PATCH 07/12] Add documentation --- docs/settings.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/settings.rst b/docs/settings.rst index 4776ce004..bd04f2813 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -140,3 +140,32 @@ Default: ``False`` # 'messages': ['This field is required.'], # } # ] + + +``DJANGO_CHOICE_FIELD_ENUM_V3_NAMING`` +-------------------------------------- + +Set to ``True`` to use the new naming format for the auto generated Enum types from Django choice fields. The new format looks like this: ``DjangoModel{app_label}{object_name}{field_name}Choices`` + +Default: ``False`` + + +``DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME`` +-------------------------------------- + +Set to a function that takes the Django choice field and returns a string to completely customise the naming for the Enum type. + +If set to a function then the ``DJANGO_CHOICE_FIELD_ENUM_V3_NAMING`` setting is ignored. + +Default: ``None`` + +.. code:: python + + def enum_naming(field): + if isinstance(field.model, User): + return f"CustomUserEnum{field.name.title()}" + return f"CustomEnum{field.name.title()}" + + GRAPHENE = { + 'DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME': enum_naming + } From 8fb8b1707857e3aa63b5f364bdacfcafc884a1d0 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Wed, 22 Jan 2020 11:52:40 +0000 Subject: [PATCH 08/12] Use format instead of f strings --- graphene_django/tests/test_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index a3261df79..d5ca88fa8 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -533,7 +533,7 @@ class Query(ObjectType): def test_django_objecttype_choices_custom_enum_name(self, PetModel): def custom_name(field): - return f"CustomEnum{field.name.title()}" + return "CustomEnum{}".format(field.name.title()) graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME = custom_name From 82fcb37d8b32e9f2d9bf256720785cbfa99203fb Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Thu, 30 Jan 2020 10:07:31 +0000 Subject: [PATCH 09/12] Update graphene_django/converter.py Co-Authored-By: Syrus Akbary --- graphene_django/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index a986d7ac8..604e597e4 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -75,7 +75,7 @@ def generate_enum_name(django_model_meta, field): ): name = graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME(field) elif graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING is True: - name = "DjangoModel{app_label}{object_name}{field_name}Choices".format( + name = "{app_label}{object_name}{field_name}Choices".format( app_label=to_camel_case(django_model_meta.app_label.title()), object_name=django_model_meta.object_name, field_name=to_camel_case(field.name.title()), From e2083594d9f868cd1d444851e9c67c43f020ecec Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Thu, 30 Jan 2020 10:11:05 +0000 Subject: [PATCH 10/12] Fix tests --- graphene_django/tests/test_converter.py | 4 ++-- graphene_django/tests/test_types.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index 1eb1e3ffa..7f84de3ae 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -340,7 +340,7 @@ def test_generate_enum_name(): # Simple case field = graphene.Field(graphene.String, name="type") model_meta = MockDjangoModelMeta(app_label="users", object_name="User") - assert generate_enum_name(model_meta, field) == "DjangoModelUsersUserTypeChoices" + assert generate_enum_name(model_meta, field) == "UsersUserTypeChoices" # More complicated multiple work case field = graphene.Field(graphene.String, name="fizz_buzz") @@ -349,7 +349,7 @@ def test_generate_enum_name(): ) assert ( generate_enum_name(model_meta, field) - == "DjangoModelSomeLongAppNameSomeObjectFizzBuzzChoices" + == "SomeLongAppNameSomeObjectFizzBuzzChoices" ) graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = False diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index d5ca88fa8..0fd20f428 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -514,19 +514,19 @@ class Query(ObjectType): query: Query } - enum CustomEnumKind { - CAT - DOG - } - type PetModelKind { id: ID! - kind: CustomEnumKind! + kind: TestsPetModelKindChoices! } type Query { pet: PetModelKind } + + enum TestsPetModelKindChoices { + CAT + DOG + } """ ) graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = False From d0e3a04ac7a4894cb93da6dcb0ab4222c2d6f7e3 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Thu, 30 Jan 2020 10:11:54 +0000 Subject: [PATCH 11/12] Update docs --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index bd04f2813..3059bfd67 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -145,7 +145,7 @@ Default: ``False`` ``DJANGO_CHOICE_FIELD_ENUM_V3_NAMING`` -------------------------------------- -Set to ``True`` to use the new naming format for the auto generated Enum types from Django choice fields. The new format looks like this: ``DjangoModel{app_label}{object_name}{field_name}Choices`` +Set to ``True`` to use the new naming format for the auto generated Enum types from Django choice fields. The new format looks like this: ``{app_label}{object_name}{field_name}Choices`` Default: ``False`` From 9cff36573c81c941c3ca762914f2e715af90f4e7 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 23 Feb 2020 09:04:57 +0000 Subject: [PATCH 12/12] Import function through import_string function --- docs/settings.rst | 5 +++-- graphene_django/converter.py | 11 +++++++---- graphene_django/tests/test_types.py | 15 +++++++++------ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 3059bfd67..5a7e4c9da 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -153,7 +153,7 @@ Default: ``False`` ``DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME`` -------------------------------------- -Set to a function that takes the Django choice field and returns a string to completely customise the naming for the Enum type. +Define the path of a function that takes the Django choice field and returns a string to completely customise the naming for the Enum type. If set to a function then the ``DJANGO_CHOICE_FIELD_ENUM_V3_NAMING`` setting is ignored. @@ -161,11 +161,12 @@ Default: ``None`` .. code:: python + # myapp.utils def enum_naming(field): if isinstance(field.model, User): return f"CustomUserEnum{field.name.title()}" return f"CustomEnum{field.name.title()}" GRAPHENE = { - 'DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME': enum_naming + 'DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME': "myapp.utils.enum_naming" } diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 604e597e4..bd8f79d03 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -1,6 +1,7 @@ from collections import OrderedDict from django.db import models from django.utils.encoding import force_str +from django.utils.module_loading import import_string from graphene import ( ID, @@ -70,10 +71,12 @@ def description(self): def generate_enum_name(django_model_meta, field): - if graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME and callable( - graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME - ): - name = graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME(field) + if graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME: + # Try and import custom function + custom_func = import_string( + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME + ) + name = custom_func(field) elif graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING is True: name = "{app_label}{object_name}{field_name}Choices".format( app_label=to_camel_case(django_model_meta.app_label.title()), diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 0fd20f428..888521f78 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -388,6 +388,10 @@ class Meta: assert len(record) == 0 +def custom_enum_name(field): + return "CustomEnum{}".format(field.name.title()) + + class TestDjangoObjectType: @pytest.fixture def PetModel(self): @@ -532,10 +536,9 @@ class Query(ObjectType): graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = False def test_django_objecttype_choices_custom_enum_name(self, PetModel): - def custom_name(field): - return "CustomEnum{}".format(field.name.title()) - - graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME = custom_name + graphene_settings.DJANGO_CHOICE_FIELD_ENUM_CUSTOM_NAME = ( + "graphene_django.tests.test_types.custom_enum_name" + ) class PetModelKind(DjangoObjectType): class Meta: @@ -553,14 +556,14 @@ class Query(ObjectType): query: Query } - enum DjangoModelTestsPetModelKindChoices { + enum CustomEnumKind { CAT DOG } type PetModelKind { id: ID! - kind: DjangoModelTestsPetModelKindChoices! + kind: CustomEnumKind! } type Query {