graphene-django icon indicating copy to clipboard operation
graphene-django copied to clipboard

Duplicate types when using SerializerMutation with a Model having "choices"

Open ramonwenger opened this issue 3 years ago • 2 comments

Note: for support questions, please use stackoverflow. This repository's issues are reserved for feature requests and bug reports.

  • What is the current behavior?

When defining a Mutation with the parent SerializerMutation, graphene will try to generate two types with the same name, resulting in the error AssertionError: Found different types with the same name in the schema: xxx, xxx.

  • If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via a github repo, https://repl.it or similar.

Define these classes

class Demo(models.Model):
    class YesNoChoices(models.TextChoices):
        YES = "y"
        NO = "n"

    field_with_choices = models.CharField(max_length=1, choices=YesNoChoices)

class DemoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Demo
        fields = ["field_with_choices"]

class DemoMutation(SerializerMutation):
    class Meta:
        serializer_class = DemoSerializer

class Mutation(object):
    demo_mutation = DemoMutation.Field()

then run

python manage.py graphql_schema
  • What is the expected behavior?

Types should be created in a clean manner without naming conflicts, resulting in a valid schema.

  • What is the motivation / use case for changing the behavior?

  • Please tell us about your environment:

    • Version: graphene-django: 2.15.0, python 3.10.6
    • Platform: Ubuntu 22.04
  • Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow)

Most likely relates to graphql-python/graphene#1384, where Enums are used. I cannot seem influence how the SerializerMutation handles the choices, however.

ramonwenger avatar Nov 22 '22 14:11 ramonwenger

This is unlikely to be related to graphene, but rather an issue of the SerializerMutation in Graphene Django. Graphene itself does not automatically generate any enums and as such is unlikely the root cause of this issue. Moving to graphene-django.

You could probably look into how the serializer mutation generates the input graphene types from the models. I'm not an expert with graphene-django, but in graphene-sqlalchemy there's an enum registry in registry.py. Maybe SerializerMutation instead calls fromEnum again instead of looking at the registry, causing the error because the enum was already generated for your Schema Models.

erikwrede avatar Nov 23 '22 20:11 erikwrede

The issue is the following: As I expected, the Serializer tries to get a matching graphene type from the model field: https://github.com/graphql-python/graphene-django/blob/4517e3222499a1aca7c1110204ce5b27d9c911be/graphene_django/rest_framework/serializer_converter.py#L13-L15

When it hits a Choices field, it calls the django converter for enum fields:

https://github.com/graphql-python/graphene-django/blob/4517e3222499a1aca7c1110204ce5b27d9c911be/graphene_django/rest_framework/serializer_converter.py#L159-L163

Which will always create a new Enum type, disregarding wether or not the current Choices type already has a corresponding graphene Enum. https://github.com/graphql-python/graphene-django/blob/4517e3222499a1aca7c1110204ce5b27d9c911be/graphene_django/converter.py#L89-L100

At this point we can assume that the Choices type was already converted to a graphene Enum once, as part of the Schema for the Model. Now the SerializerMutation causes a second conversion, leading to duplicate types with the same name. This can be fixed using a registry, please check out graphene-sqlalchemy's registry.py and converter.py for further reference 🙂

erikwrede avatar Nov 23 '22 21:11 erikwrede