diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 8b93d17..fea0b42 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -22,6 +22,7 @@ from graphene.types.json import JSONString 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 convert_choices_to_named_enum_with_descriptions(name, choices): 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 9a5e8a9..5582b03 100644 --- a/graphene_django/settings.py +++ b/graphene_django/settings.py @@ -36,6 +36,8 @@ DEFAULTS = { # 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 c32f46c..7a37086 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -9,6 +9,7 @@ from graphene import Connection, Field, Interface, ObjectType, Schema, String 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 TestDjangoObjectType: } """ ) + + 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