class User(DjangoObjectType):
class Meta:
model = get_user_model()
only_fields = ['signup_site_version']
class Query(graphene.ObjectType):
user = graphene.Field(User)
def resolve_user(self, args, context, info):
return user_from_info(info) # return django user from context
@python_2_unicode_compatible
class User(AbstractUser):
(...)
signup_site_version_choices = [(1, u'site 1'), (2, u'site 2')]
signup_site_version = models.IntegerField(choices=signup_site_version_choices)
query {
user {
signupSiteVersion
}
}
{
"data": {
"user": {
"signupSiteVersion": "A_1"
}
}
}
A copy-paste from where the weird value is born:
def convert_choice_name(name):
name = to_const(force_text(name))
try:
assert_valid_name(name)
except AssertionError:
name = "A_%s" % name
return name
We've had similar problems in the old graphene (< 1.0): https://github.com/graphql-python/graphene/issues/134
The output is "A_1", because the field converter assumes django choices are tuples (id, name) where name is a constant name (not containing spaces etc.) or is convertible to a valid constant name. For some reason it is not successful while doing that for "site 1", but that is not an issue. The problem is it assumes we would like to do that.
In our django application (I suppose it is the norm) we use the second tuple element as a human-readable label. It means that in most cases replacing space with an underscore will do the work, but
in the other names are still bound to be long and there is no character we can safely assume the name won't contain (including hyphens, all native character varieties etc.).
The Enum fields are certainly nice, as their values are schema-validated, to say the least, but I doubt automatic conversion should be the only possible behaviour.
My personal opinion is that it should be easy to make choices an Enum, but that it shouldn't be the default. The requirements of django choices are much, much more permissive than those of an Enum (in either Python or GraphQL)
I also ran into this but I thought it were intensional.
Hi,
How I can overwrite the "A_1" output?
Thanks
Choices are also converted to uppercase, which makes it difficult to manage during mutations, especially if the choices were mixed upper and lower case. There should be an option to just leave your choices alone.
Maybe someone adds GRAPHENE_CONVERT_CHOICES_TO_ENUMS = False setting to graphene_django once.
Until then, you can opt out with monkey-patch somewhere before schema is imported, for example in settings file.
Patch: https://gist.github.com/denis-ryzhkov/fcb944f6ebfad4775efb74848703f0d7
What would be the desired behavior for enums? I think it makes sense to handle them automatically unless explicitly defined on in the schema but maybe we can introduce some config to handle the different use cases.
Way I see it there are 3 options:
There are quite a few issues related to this behavior:
I like the simplicity of https://github.com/graphql-python/graphene-django/pull/209 but don't like that it relies on another dependency and requires changes in the model layer.
After reading the various proposals, I think a hybrid approach might work.
GRAPHENE_DISABLE_ENUM_CONVERSION, False by defaultPlease add one more step to the hybrid approach above:
GRAPHENE_DISABLE_ENUM_CONVERSION being False by default for backward compatibility. When set to True, it will save a user from a lot of boilerplate code and effort of setting Meta.disable_enum_conversion lists and keeping them updated@denis-ryzhkov updated the original post鈥攔emoved the list approach and replaced with the global setting. Custom resolvers can be used instead of Meta config list.
Any updates on this? Using the monkeypatch for now, but that's really sketchy.
@subwindow we've made no development process on this but it looks like we've agreed on the approach we will take, as @mvanlonden said:
We are currently focused on setting up governance and organising the support around the graphene project as a whole, when that is more stable this should be one of the first features we tackle. I want it too, so I can't wait to get started on it!
There's also an issue with enum fields containing non-English letters and throwing an error. I guess a way to just disable the conversion overall would be fine, there are many edge cases like that that this conversion doesn't cover
BTW, the integration with Django filter lib is weird too, ChoiceFilter is used by default which shows all results for non-existent choices, had to also switch to CharFilter
Looks like we need tests with non-english choices.
@kaglowka v2.4.0 contains a new feature which allows you to turn off automatic enum creation on a case by case basis: http://docs.graphene-python.org/projects/django/en/latest/queries/#choices-to-enum-conversion
If I want to use the converted choices Enum as the filter argument.
How I can easily define it in the query?
Here is a way to do it:
class Label(BaseModel):
TYPES = [(x, x) for x in ("AAA", "BBB")]
name = models.CharField(max_length=256)
type = models.CharField(max_length=8, null=True, choices=TYPES)
class LabelQL(DjangoObjectType):
class Meta:
model = Label
only_fields = ("name", "type")
name = "Label"
LabelType = LabelQL._meta.fields["type"].type # That is tricky
class Query(graphene.ObjectType):
labels = graphene.List(LabelQL, types=graphene.List(LabelType))
def resolve_labels(root, info, types=None):
qs = Label.objects.all()
if types and len(types) > 0:
qs = qs.filter(type__in=types)
return qs
I have to get the converted type from LabelQL._meta.fields["type"].type
I there any natural way to use LabelType in the query?
@jkimbo What about users using Flask? How can we turn this feature off?
@levrik you will have to raise that issue with the graphene-flask repo
Why is this closed? I still have this issue.
@Suor because Graphene Django now lets you turn off the automatic enum conversion: http://docs.graphene-python.org/projects/django/en/latest/queries/#choices-to-enum-conversion
@o3o3o
I there any natural way to use LabelType in the query?
I found that this works
ServiceStage = Service._meta.fields["stage"].type
...
Query:
orf_service_by_organization_id = graphene.List(Service,
stage=graphene.Argument(ServiceStage, required=False, default_value='A'),
id = graphene.UUID(required=False))
Hello I have managed to make the Choices field use an Enum,
Question:
How do I query the available choices ?
In the past I have done
# Here the self is an empty form instance
class UserProfileFormChoicesType(graphene.ObjectType):
clinical_expertise = generic.GenericScalar()
psychosocial_expertise = generic.GenericScalar()
def resolve_clinical_expertise(self, info):
return [i for i in self.fields['clinical_expertise'].choices]
def resolve_psychosocial_expertise(self, info):
return [i for i in self.fields['psychosocial_expertise'].choices]
# The form for the choices
class UserProfileSettingsForm(forms.ModelForm):
class Meta:
model = User
fields = [ ... ]
I know that i can introspect the whole schema with
query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
but how do I introspect the specific type generated for the Enum choices ?
Is using a form still the best choice ?
graphene.Field(generic.GenericScalar)
# resolve to this
Service._meta.get_field('stage').choices
Most helpful comment
Choices are also converted to uppercase, which makes it difficult to manage during mutations, especially if the choices were mixed upper and lower case. There should be an option to just leave your choices alone.