Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions graphene_django/converter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from collections import OrderedDict
from functools import singledispatch
from functools import singledispatch, partial, wraps

from django.db import models
from django.utils.encoding import force_str
from django.utils.functional import Promise
from django.utils.module_loading import import_string

from graphene import (
ID,
UUID,
Expand All @@ -22,6 +23,7 @@
Time,
Decimal,
)
from graphene.types.resolver import get_default_resolver
from graphene.types.json import JSONString
from graphene.utils.str_converters import to_camel_case
from graphql import GraphQLError, assert_valid_name
Expand All @@ -33,6 +35,24 @@
from .utils.str_converters import to_const


class BlankValueField(Field):
def get_resolver(self, parent_resolver):
resolver = self.resolver or parent_resolver

# create custom resolver
def blank_field_wrapper(func):
@wraps(func)
def wrapped_resolver(*args, **kwargs):
return_value = func(*args, **kwargs)
if return_value == "":
return None
return return_value

return wrapped_resolver

return blank_field_wrapper(resolver)


def convert_choice_name(name):
name = to_const(force_str(name))
try:
Expand Down Expand Up @@ -71,7 +91,8 @@ class EnumWithDescriptionsType(object):
def description(self):
return str(named_choices_descriptions[self.name])

return Enum(name, list(named_choices), type=EnumWithDescriptionsType)
return_type = Enum(name, list(named_choices), type=EnumWithDescriptionsType)
return return_type


def generate_enum_name(django_model_meta, field):
Expand Down Expand Up @@ -108,11 +129,12 @@ def convert_django_field_with_choices(
return converted
choices = getattr(field, "choices", None)
if choices and convert_choices_to_enum:
enum = convert_choice_field_to_enum(field)
EnumCls = convert_choice_field_to_enum(field)
required = not (field.blank or field.null)
converted = enum(

converted = EnumCls(
description=get_django_field_description(field), required=required
)
).mount_as(BlankValueField)
else:
converted = convert_django_field(field, registry)
if registry is not None:
Expand Down
43 changes: 41 additions & 2 deletions graphene_django/tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ class TranslatedModel(models.Model):
class Meta:
app_label = "test"

graphene_type = convert_django_field_with_choices(field)
assert isinstance(graphene_type, graphene.Enum)
graphene_type = convert_django_field_with_choices(field).type.of_type
assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices"
assert graphene_type._meta.enum.__members__["ES"].value == "es"
assert graphene_type._meta.enum.__members__["ES"].description == "Spanish"
Expand Down Expand Up @@ -418,3 +417,43 @@ def test_generate_v2_enum_name(graphene_settings):
app_label="some_long_app_name", object_name="SomeObject"
)
assert generate_enum_name(model_meta, field) == "SomeObjectFizzBuzz"


def test_choice_enum_blank_value():
"""Test that choice fields with blank values work"""

class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
fields = (
"first_name",
"a_choice",
)

class Query(graphene.ObjectType):
reporter = graphene.Field(ReporterType)

def resolve_reporter(root, info):
return Reporter.objects.first()

schema = graphene.Schema(query=Query)

# Create model with empty choice option
Reporter.objects.create(
first_name="Bridget", last_name="Jones", email="[email protected]"
)

result = schema.execute(
"""
query {
reporter {
firstName
aChoice
}
}
"""
)
assert not result.errors
assert result.data == {
"reporter": {"firstName": "Bridget", "aChoice": None},
}