Skip to content

Commit bcc7f85

Browse files
zbyte64jkimbo
andauthored
Add BlankField and mount enums using it v3 (#1096)
* Add BlankField and mount enums using it * fix lint error from duplicate import Co-authored-by: Jonathan Kim <[email protected]>
1 parent 10e48c2 commit bcc7f85

File tree

2 files changed

+68
-7
lines changed

2 files changed

+68
-7
lines changed

graphene_django/converter.py

+27-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from collections import OrderedDict
2-
from functools import singledispatch
2+
from functools import singledispatch, partial, wraps
33

44
from django.db import models
55
from django.utils.encoding import force_str
66
from django.utils.functional import Promise
77
from django.utils.module_loading import import_string
8+
89
from graphene import (
910
ID,
1011
UUID,
@@ -22,6 +23,7 @@
2223
Time,
2324
Decimal,
2425
)
26+
from graphene.types.resolver import get_default_resolver
2527
from graphene.types.json import JSONString
2628
from graphene.utils.str_converters import to_camel_case
2729
from graphql import GraphQLError, assert_valid_name
@@ -33,6 +35,24 @@
3335
from .utils.str_converters import to_const
3436

3537

38+
class BlankValueField(Field):
39+
def get_resolver(self, parent_resolver):
40+
resolver = self.resolver or parent_resolver
41+
42+
# create custom resolver
43+
def blank_field_wrapper(func):
44+
@wraps(func)
45+
def wrapped_resolver(*args, **kwargs):
46+
return_value = func(*args, **kwargs)
47+
if return_value == "":
48+
return None
49+
return return_value
50+
51+
return wrapped_resolver
52+
53+
return blank_field_wrapper(resolver)
54+
55+
3656
def convert_choice_name(name):
3757
name = to_const(force_str(name))
3858
try:
@@ -71,7 +91,8 @@ class EnumWithDescriptionsType(object):
7191
def description(self):
7292
return str(named_choices_descriptions[self.name])
7393

74-
return Enum(name, list(named_choices), type=EnumWithDescriptionsType)
94+
return_type = Enum(name, list(named_choices), type=EnumWithDescriptionsType)
95+
return return_type
7596

7697

7798
def generate_enum_name(django_model_meta, field):
@@ -108,11 +129,12 @@ def convert_django_field_with_choices(
108129
return converted
109130
choices = getattr(field, "choices", None)
110131
if choices and convert_choices_to_enum:
111-
enum = convert_choice_field_to_enum(field)
132+
EnumCls = convert_choice_field_to_enum(field)
112133
required = not (field.blank or field.null)
113-
converted = enum(
134+
135+
converted = EnumCls(
114136
description=get_django_field_description(field), required=required
115-
)
137+
).mount_as(BlankValueField)
116138
else:
117139
converted = convert_django_field(field, registry)
118140
if registry is not None:

graphene_django/tests/test_converter.py

+41-2
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,7 @@ class TranslatedModel(models.Model):
164164
class Meta:
165165
app_label = "test"
166166

167-
graphene_type = convert_django_field_with_choices(field)
168-
assert isinstance(graphene_type, graphene.Enum)
167+
graphene_type = convert_django_field_with_choices(field).type.of_type
169168
assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices"
170169
assert graphene_type._meta.enum.__members__["ES"].value == "es"
171170
assert graphene_type._meta.enum.__members__["ES"].description == "Spanish"
@@ -418,3 +417,43 @@ def test_generate_v2_enum_name(graphene_settings):
418417
app_label="some_long_app_name", object_name="SomeObject"
419418
)
420419
assert generate_enum_name(model_meta, field) == "SomeObjectFizzBuzz"
420+
421+
422+
def test_choice_enum_blank_value():
423+
"""Test that choice fields with blank values work"""
424+
425+
class ReporterType(DjangoObjectType):
426+
class Meta:
427+
model = Reporter
428+
fields = (
429+
"first_name",
430+
"a_choice",
431+
)
432+
433+
class Query(graphene.ObjectType):
434+
reporter = graphene.Field(ReporterType)
435+
436+
def resolve_reporter(root, info):
437+
return Reporter.objects.first()
438+
439+
schema = graphene.Schema(query=Query)
440+
441+
# Create model with empty choice option
442+
Reporter.objects.create(
443+
first_name="Bridget", last_name="Jones", email="[email protected]"
444+
)
445+
446+
result = schema.execute(
447+
"""
448+
query {
449+
reporter {
450+
firstName
451+
aChoice
452+
}
453+
}
454+
"""
455+
)
456+
assert not result.errors
457+
assert result.data == {
458+
"reporter": {"firstName": "Bridget", "aChoice": None},
459+
}

0 commit comments

Comments
 (0)