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 <jkimbo@gmail.com>
This commit is contained in:
Jason Kraus 2021-01-11 16:34:50 -08:00 committed by GitHub
parent 10e48c27b7
commit bcc7f85dad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 7 deletions

View File

@ -1,10 +1,11 @@
from collections import OrderedDict from collections import OrderedDict
from functools import singledispatch from functools import singledispatch, partial, wraps
from django.db import models from django.db import models
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.functional import Promise from django.utils.functional import Promise
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
from graphene import ( from graphene import (
ID, ID,
UUID, UUID,
@ -22,6 +23,7 @@ from graphene import (
Time, Time,
Decimal, Decimal,
) )
from graphene.types.resolver import get_default_resolver
from graphene.types.json import JSONString from graphene.types.json import JSONString
from graphene.utils.str_converters import to_camel_case from graphene.utils.str_converters import to_camel_case
from graphql import GraphQLError, assert_valid_name from graphql import GraphQLError, assert_valid_name
@ -33,6 +35,24 @@ from .settings import graphene_settings
from .utils.str_converters import to_const 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): def convert_choice_name(name):
name = to_const(force_str(name)) name = to_const(force_str(name))
try: try:
@ -71,7 +91,8 @@ def convert_choices_to_named_enum_with_descriptions(name, choices):
def description(self): def description(self):
return str(named_choices_descriptions[self.name]) 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): def generate_enum_name(django_model_meta, field):
@ -108,11 +129,12 @@ def convert_django_field_with_choices(
return converted return converted
choices = getattr(field, "choices", None) choices = getattr(field, "choices", None)
if choices and convert_choices_to_enum: 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) required = not (field.blank or field.null)
converted = enum(
converted = EnumCls(
description=get_django_field_description(field), required=required description=get_django_field_description(field), required=required
) ).mount_as(BlankValueField)
else: else:
converted = convert_django_field(field, registry) converted = convert_django_field(field, registry)
if registry is not None: if registry is not None:

View File

@ -164,8 +164,7 @@ def test_field_with_choices_convert_enum():
class Meta: class Meta:
app_label = "test" app_label = "test"
graphene_type = convert_django_field_with_choices(field) graphene_type = convert_django_field_with_choices(field).type.of_type
assert isinstance(graphene_type, graphene.Enum)
assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices" assert graphene_type._meta.name == "TestTranslatedModelLanguageChoices"
assert graphene_type._meta.enum.__members__["ES"].value == "es" assert graphene_type._meta.enum.__members__["ES"].value == "es"
assert graphene_type._meta.enum.__members__["ES"].description == "Spanish" assert graphene_type._meta.enum.__members__["ES"].description == "Spanish"
@ -418,3 +417,43 @@ def test_generate_v2_enum_name(graphene_settings):
app_label="some_long_app_name", object_name="SomeObject" app_label="some_long_app_name", object_name="SomeObject"
) )
assert generate_enum_name(model_meta, field) == "SomeObjectFizzBuzz" 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="bridget@example.com"
)
result = schema.execute(
"""
query {
reporter {
firstName
aChoice
}
}
"""
)
assert not result.errors
assert result.data == {
"reporter": {"firstName": "Bridget", "aChoice": None},
}