Hi,
When you try to create a model with choices field and then create a second model which inherit from the previous one, you will receive error while schema generating.
Here you have a simple project with models and basic configuration. Try to generate schema and you will get following error:
AssertionError: Found different types with the same name in the schema: PageType, PageType.
It seems that it is unable to inherit models with choices fields.
Getting same
AssertionError: Found different types with the same name in the schema: PartMarketState, PartMarketState.
This is using django-fsm (functional state machine) which is guess creates set of enums as well
I getting a same error.
File "E:\pythonvenv\django11\lib\site-packages\graphqltype\definition.py", line 180, in fields
return define_field_map(self, self._fields)
File "E:\pythonvenv\django11\lib\site-packages\graphqltype\definition.py", line 189, in define_field_map
field_map = field_map()
File "E:\pythonvenv\django11\lib\site-packages\graphenetypestypemap.py", line 235, in construct_fields_for_type
map = self.reducer(map, field.type)
File "E:\pythonvenv\django11\lib\site-packages\graphenetypestypemap.py", line 72, in reducer
return self.graphene_reducer(map, type)
File "E:\pythonvenv\django11\lib\site-packages\graphenetypestypemap.py", line 77, in graphene_reducer
return self.reducer(map, type.of_type)
File "E:\pythonvenv\django11\lib\site-packages\graphenetypestypemap.py", line 72, in reducer
return self.graphene_reducer(map, type)
File "E:\pythonvenv\django11\lib\site-packages\graphenetypestypemap.py", line 83, in graphene_reducer
).format(_type.graphene_type, type)
AssertionError: Found different types with the same name in the schema: UserUserType, UserUserType.
class User(BDAbstractUser):
TYPE_CHOICES = [('agent', 'agent'), ('nomal', 'nomal.'), ('superuser',
""" 'superuser')]
user_type = models.CharField(max_length=10, blank=True)
"""
user_type = models.CharField(
_('user type'),
max_length=10,
choices=TYPE_CHOICES,
default='nomal',
help_text=_('need user type'))
It seems you're not allowed to include type in your field's name. I tried type = models.CharField() and foo_type = models.CharField() and both caused that error.
When I changed the field's name to foo the error was gone.
Still have this issue after renaming of models fields.
But this hack works for me https://github.com/graphql-python/graphene-django/issues/87#issuecomment-328829397
Is it documented anywhere that we can not use field name type in models when using this library?
@darkowic I was wondering why I was getting this error. Now that you mention, the problematic model has a type field in it.
This is quite a glaring bug to still have.
What can be done about it? Thoughts?
When graphene_django converts a field with choices to graphene.Enum, it creates a new type for this field.
If it was type field of model Foo, new autogenerated type will be FooType.
And you probably already have your own
class FooType(DjangoObjectType):
class Meta:
model = Foo
So there is AssertionError: Found different types with the same name in the schema: FooType, FooType.
This conversion raised a lot of questions already: https://github.com/graphql-python/graphene-django/issues?q=is%3Aissue+choices
Maybe someone adds GRAPHENE_CONVERT_CHOICES_TO_ENUMS = False setting to graphene_django once.
Until then I am going to monkey-patch it somewhere before schema is imported, for example in settings file.
Patch: https://gist.github.com/denis-ryzhkov/fcb944f6ebfad4775efb74848703f0d7
@denis-ryzhkov thanks for the investigation! You're right, the issues seems to be that the auto naming of the Enum field that a Django choice field gets converted to is likely to clash with an existing type in your schema since it's just the object type name plus the field name: https://github.com/graphql-python/graphene-django/blob/a480a39713d3392dc3a7cee9565989a713d05856/graphene_django/converter.py#L50
I think the fix for that is make the generated name more explicit and less likely to clash with anything in the schema. Something like DjangoModel{object_name}{field_name}Choices (e.g. DjangoModelFooTypeChoices).
Separately, disabling the conversion of Django choice fields to Enums is a good idea since it's not always desired. Though I think it's probably something that should be done on a field level rather than globally.
I fixed it by just using the import statement. I imported the type from another class instead of rewriting it again.
But that maybe does not solve the issues if you overwrite a class
I have also had this issue and @denis-ryzhkov explanation helped me resolve the issue. I have a model Organization with field type with choices in it. For schema I had the following:
class OrganizationType(DjangoObjectType):
class Meta:
model = Organization
As a result, I was getting:
AssertionError: Found different types with the same name in the schema: OrganizationType, OrganizationType.
After reading through this, I just changed the class name to OrganizationGQLType. Now, everyhing works as expected. If this decision is not going to be changed, I think it would be beneficial to add this to the docs to clear out the confusion.
I also encountered the same error and renaming the field type into something fixed my problem
Is it documented anywhere that we can not use field name type in models when using this library?
It's generally not a good idea to use this as a variable name in Python, as you're overwriting the built-in type keyword. So this isn't documented in this package because it's probably more of a Python gotcha?
as you're overwriting the built-in
typekeyword
There is a difference between reserved keywords that cannot be used as identifiers vs built-in identifiers that are always available (either without import or via builtins module)
Both type and id are examples of built-in identifiers, and id is widely shadowed, e.g. in Django ORM
This shadowing usually happens on the class definition level, where built-in functions like type() and id() are of no use, but class fields with these names are very natural
Once such class fields are defined, item.id and item.type (including self.id and self.type) don't shadow built-ins any more
Imagine graphene-django expected you to never have id field in your classes and also felt no need to document this expectation and naming conflict it leads to, just because id is a built-in identifier - that would raise a ton of issues instantly, but even type raised multiple issues here
So please either document this poor design decision and its workaround or solve it somehow
There is a difference between reserved keywords that cannot be used as identifiers vs built-in identifiers that are always available (either without import or via builtins module)
I mixed them up, woops!
So please either document this poor design decision and its workaround or solve it somehow
I appreciate this hasn't been looked at yet. I'm a new collaborator to this project, I'll see what I can do to make sure this bug is added to a list of top priority things.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Looks like this is still an issue. Don't close
I think this can be solved by adding double underscore or something similar to the name (e.g “__OrganizationType” instead of “OrganizationType”). I just got curious about this to be honest. Why does a choice based field have a type? Is it possible to completely remove this auto-generated field type for choice field?
@GasimGasimzada there is an option in master (not yet released) that allows you to turn off the automatic choice to enum conversion: https://github.com/graphql-python/graphene-django/pull/674
I am trying to figure out why our unit tests don't catch this. We have a test model Reporter which has a field reporter_type which has options and it seems to work. See: https://github.com/graphql-python/graphene-django/blob/master/graphene_django/tests/models.py#L45
@zbyte64 Isn't it just if the field is named "type"? I have the same issue.
To fix it you have to use ConvertedPageType = Enum.from_enum(PageType) only once, and use ConvertedPageType everywhere
To fix it you have to use
ConvertedPageType = Enum.from_enum(PageType)only once, and useConvertedPageTypeeverywhere
This doesn't work if you are using RelaySerializerMutation, as it will create a type on its own
Related issue: meta.object_name is not unique enough, since it's possible to have multiple models with the same name in different Django apps which are running at the same time.
I think the fix for that is make the generated name more explicit and less likely to clash with anything in the schema. Something like
DjangoModel{object_name}{field_name}Choices(e.g.DjangoModelFooTypeChoices).
So this is not enough, it should be DjangoModel{app_label}{object_name}{field_name}Choices.
Related issue:
meta.object_nameis not unique enough, since it's possible to have multiple models with the same name in different Django apps which are running at the same time.I think the fix for that is make the generated name more explicit and less likely to clash with anything in the schema. Something like
DjangoModel{object_name}{field_name}Choices(e.g.DjangoModelFooTypeChoices).So this is not enough, it should be
DjangoModel{app_label}{object_name}{field_name}Choices.
I agree. But maybe check first for name collisions first? Otherwise new and very simple projects will have over-complicated names.
Related issue:
meta.object_nameis not unique enough, since it's possible to have multiple models with the same name in different Django apps which are running at the same time.I think the fix for that is make the generated name more explicit and less likely to clash with anything in the schema. Something like
DjangoModel{object_name}{field_name}Choices(e.g.DjangoModelFooTypeChoices).So this is not enough, it should be
DjangoModel{app_label}{object_name}{field_name}Choices.I agree. But maybe check first for name collisions first? Otherwise new and very simple projects will have over-complicated names.
Very good points and I especially like the suggestion of checking for name collisions first to progressively improve this. That way it’s not a breaking change either. I’ll try and create a PR for this as soon as possible.
@jkimbo have you had a chance to work on that? Just ran into this, seems like your solution would solve my problems.
@MisterGlass I have had a look and unfortunately I don’t it would be possible to check for name collisions since the enum name is defined before it has access to the schema. I think the only way to solve this would be an opt in flag to change the naming generation. Currently not sure if this should be per object type or globally for the whole schema. Anyone have any suggestions?
I think using the long names without checking for name collisions is fine. Certainly better than the collisions IMO.
@MisterGlass @arielnmz would it be very disruptive for you we added a global option to change all enums generated from field choices to the new long name format? It would be all or nothing.
@MisterGlass @arielnmz would it be very disruptive for you we added a global option to change all enums generated from field choices to the new long name format? It would be all or nothing.
Not at all. I think its an excellent middle ground and by the way aligns pretty well with the actual workarounds I've put in place (at least in my case).
@jkimbo Sounds fine to me. Another thing I've seen some frameworks do is Just have a configurable string that is part of the generated names. Default is often the project name (EG Graphene, so our example of PageType would be PageGrapheneType) , but to keep existing deployments the same you can default to empty string. Then all people with these conflicts would have to do is override the empty string with something that won't generate a conflict.
Sorry for the delay with this but I've just created https://github.com/graphql-python/graphene-django/pull/860 which should resolve the issues in this thread. I would appreciate if people could have a look at the PR to make sure that it would solve your issue in a reasonable way.
That looks fabulous @jkimbo, thank you
I am using version 2.10.1 and this definitely hasn't been solved.
I have a field called type with choices option. I am forced to name the ObjectType anything other than ModelNameType in order to avoid conflicts.
Did I miss something? If not, then what was fixed?
@rarenatoe have you tried enabling the DJANGO_CHOICE_FIELD_ENUM_V3_NAMING option?
~@jkimbo like DJANGO_CHOICE_FIELD_ENUM_V3_NAMING = True on my settings.py?~
Ah figured it out. I had to add something like this to settings.py:
GRAPHENE = {
"DJANGO_CHOICE_FIELD_ENUM_V3_NAMING": True,
}
Might be a good idea to include this in the online docs.
@rarenatoe it is in the docs: https://docs.graphene-python.org/projects/django/en/latest/settings/#django-choice-field-enum-v3-naming
Glad you found it and it works anyway.
I am also getting this with a field called "status" (instead of "type")...
And DJANGO_CHOICE_FIELD_ENUM_V3_NAMING https://docs.graphene-python.org/projects/django/en/latest/settings/#django-choice-field-enum-v3-naming does not fix it.
It appears that this is occuring because I have a query and a SerializerMutation (for the same type) that both use the model with a choice field. Can someone reference the tests surrounding choice fields? Is there one the also uses a SeralizerMutation?
Did you try creating a type from enum and using that in your queries and mutations?11:44, 18 de agosto de 2020, Coler notifications@github.com:
I am also getting this with a field called "status" (instead of "type")...
—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or unsubscribe.
-- Sent from Yandex.Mail for mobile
@coler-j I have the same issue (using SerializerMutation). I've got a field_type. Setting DJANGO_CHOICE_FIELD_ENUM_V3_NAMING does not help
What did help was https://github.com/graphql-python/graphene-django/pull/851. Set
convert_choices_to_enum = False in your SerializerMutation class.
@arielnmz I didn't. I am more interested in an example test that shows this working.
@CBuiVNG I will try convert_choices_to_enum = False for now, I just removed the status field from my serializer (as I don't need it for current scope).
Most helpful comment
It seems you're not allowed to include
typein your field's name. I triedtype = models.CharField()andfoo_type = models.CharField()and both caused that error.When I changed the field's name to
foothe error was gone.