2020-04-06 15:21:07 +03:00
|
|
|
from functools import singledispatch
|
|
|
|
|
2017-05-28 15:48:44 +03:00
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
|
|
from rest_framework import serializers
|
|
|
|
|
|
|
|
import graphene
|
|
|
|
|
2019-09-22 23:13:12 +03:00
|
|
|
from ..converter import convert_choices_to_named_enum_with_descriptions
|
2023-08-06 01:47:00 +03:00
|
|
|
from ..registry import get_global_registry
|
2017-06-26 16:19:55 +03:00
|
|
|
from .types import DictType
|
2017-05-28 23:56:05 +03:00
|
|
|
|
2017-05-28 15:48:44 +03:00
|
|
|
|
|
|
|
@singledispatch
|
2017-06-26 13:36:48 +03:00
|
|
|
def get_graphene_type_from_serializer_field(field):
|
2017-05-28 15:48:44 +03:00
|
|
|
raise ImproperlyConfigured(
|
2023-08-09 20:48:42 +03:00
|
|
|
f"Don't know how to convert the serializer field {field} ({field.__class__}) "
|
|
|
|
"to Graphene type"
|
2017-05-28 15:48:44 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-02-07 13:17:56 +03:00
|
|
|
def convert_serializer_field(field, is_input=True, convert_choices_to_enum=True):
|
2017-05-28 15:48:44 +03:00
|
|
|
"""
|
2017-06-26 13:36:48 +03:00
|
|
|
Converts a django rest frameworks field to a graphql field
|
|
|
|
and marks the field as required if we are creating an input type
|
2017-05-28 15:48:44 +03:00
|
|
|
and the field itself is required
|
|
|
|
"""
|
|
|
|
|
2020-02-07 13:17:56 +03:00
|
|
|
if isinstance(field, serializers.ChoiceField) and not convert_choices_to_enum:
|
|
|
|
graphql_type = graphene.String
|
|
|
|
else:
|
|
|
|
graphql_type = get_graphene_type_from_serializer_field(field)
|
2017-05-28 15:48:44 +03:00
|
|
|
|
2017-07-11 21:29:30 +03:00
|
|
|
args = []
|
2018-07-20 02:51:33 +03:00
|
|
|
kwargs = {"description": field.help_text, "required": is_input and field.required}
|
2017-06-26 14:14:04 +03:00
|
|
|
|
|
|
|
# if it is a tuple or a list it means that we are returning
|
|
|
|
# the graphql type and the child type
|
|
|
|
if isinstance(graphql_type, (list, tuple)):
|
2018-07-20 02:51:33 +03:00
|
|
|
kwargs["of_type"] = graphql_type[1]
|
2017-06-26 14:14:04 +03:00
|
|
|
graphql_type = graphql_type[0]
|
|
|
|
|
2017-07-11 21:29:30 +03:00
|
|
|
if isinstance(field, serializers.ModelSerializer):
|
|
|
|
if is_input:
|
2017-08-31 19:07:05 +03:00
|
|
|
graphql_type = convert_serializer_to_input_type(field.__class__)
|
2017-07-11 21:29:30 +03:00
|
|
|
else:
|
|
|
|
global_registry = get_global_registry()
|
|
|
|
field_model = field.Meta.model
|
|
|
|
args = [global_registry.get_type_for_model(field_model)]
|
2018-02-13 13:48:43 +03:00
|
|
|
elif isinstance(field, serializers.ListSerializer):
|
|
|
|
field = field.child
|
|
|
|
if is_input:
|
2018-07-20 02:51:33 +03:00
|
|
|
kwargs["of_type"] = convert_serializer_to_input_type(field.__class__)
|
2018-02-13 13:48:43 +03:00
|
|
|
else:
|
2018-07-20 02:51:33 +03:00
|
|
|
del kwargs["of_type"]
|
2018-02-13 13:48:43 +03:00
|
|
|
global_registry = get_global_registry()
|
|
|
|
field_model = field.Meta.model
|
|
|
|
args = [global_registry.get_type_for_model(field_model)]
|
2017-07-11 21:29:30 +03:00
|
|
|
|
|
|
|
return graphql_type(*args, **kwargs)
|
2017-05-28 15:48:44 +03:00
|
|
|
|
|
|
|
|
2017-08-31 19:07:05 +03:00
|
|
|
def convert_serializer_to_input_type(serializer_class):
|
2019-07-09 16:03:11 +03:00
|
|
|
cached_type = convert_serializer_to_input_type.cache.get(
|
|
|
|
serializer_class.__name__, None
|
|
|
|
)
|
2019-07-09 11:14:04 +03:00
|
|
|
if cached_type:
|
|
|
|
return cached_type
|
2017-08-31 19:07:05 +03:00
|
|
|
serializer = serializer_class()
|
|
|
|
|
|
|
|
items = {
|
|
|
|
name: convert_serializer_field(field)
|
|
|
|
for name, field in serializer.fields.items()
|
|
|
|
}
|
2019-07-09 11:14:04 +03:00
|
|
|
ret_type = type(
|
2022-10-19 17:10:30 +03:00
|
|
|
f"{serializer.__class__.__name__}Input",
|
2017-08-31 19:07:05 +03:00
|
|
|
(graphene.InputObjectType,),
|
2018-07-20 02:51:33 +03:00
|
|
|
items,
|
2017-08-31 19:07:05 +03:00
|
|
|
)
|
2019-07-09 11:14:04 +03:00
|
|
|
convert_serializer_to_input_type.cache[serializer_class.__name__] = ret_type
|
|
|
|
return ret_type
|
|
|
|
|
|
|
|
|
|
|
|
convert_serializer_to_input_type.cache = {}
|
2017-08-31 19:07:05 +03:00
|
|
|
|
|
|
|
|
2017-06-26 13:36:48 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.Field)
|
2017-05-28 15:48:44 +03:00
|
|
|
def convert_serializer_field_to_string(field):
|
|
|
|
return graphene.String
|
|
|
|
|
|
|
|
|
2017-07-11 21:29:30 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.ModelSerializer)
|
|
|
|
def convert_serializer_to_field(field):
|
|
|
|
return graphene.Field
|
|
|
|
|
|
|
|
|
2018-02-13 13:48:43 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.ListSerializer)
|
|
|
|
def convert_list_serializer_to_field(field):
|
|
|
|
child_type = get_graphene_type_from_serializer_field(field.child)
|
|
|
|
return (graphene.List, child_type)
|
|
|
|
|
|
|
|
|
2017-06-26 13:36:48 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.IntegerField)
|
2017-05-28 15:48:44 +03:00
|
|
|
def convert_serializer_field_to_int(field):
|
|
|
|
return graphene.Int
|
|
|
|
|
|
|
|
|
2017-06-26 13:36:48 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.BooleanField)
|
2017-05-28 15:48:44 +03:00
|
|
|
def convert_serializer_field_to_bool(field):
|
|
|
|
return graphene.Boolean
|
|
|
|
|
|
|
|
|
2017-06-26 13:36:48 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.FloatField)
|
2017-05-28 15:48:44 +03:00
|
|
|
def convert_serializer_field_to_float(field):
|
|
|
|
return graphene.Float
|
2017-06-26 14:14:04 +03:00
|
|
|
|
|
|
|
|
2022-01-18 17:03:08 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.DecimalField)
|
|
|
|
def convert_serializer_field_to_decimal(field):
|
|
|
|
return graphene.Decimal
|
|
|
|
|
|
|
|
|
2017-07-11 21:35:12 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.DateTimeField)
|
2017-12-18 20:33:42 +03:00
|
|
|
def convert_serializer_field_to_datetime_time(field):
|
2017-07-11 21:35:12 +03:00
|
|
|
return graphene.types.datetime.DateTime
|
|
|
|
|
|
|
|
|
2017-12-05 23:04:29 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.DateField)
|
|
|
|
def convert_serializer_field_to_date_time(field):
|
|
|
|
return graphene.types.datetime.Date
|
|
|
|
|
|
|
|
|
2017-07-11 21:35:12 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.TimeField)
|
|
|
|
def convert_serializer_field_to_time(field):
|
|
|
|
return graphene.types.datetime.Time
|
|
|
|
|
|
|
|
|
2017-06-26 14:14:04 +03:00
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.ListField)
|
|
|
|
def convert_serializer_field_to_list(field, is_input=True):
|
|
|
|
child_type = get_graphene_type_from_serializer_field(field.child)
|
|
|
|
return (graphene.List, child_type)
|
2017-06-26 16:19:55 +03:00
|
|
|
|
|
|
|
|
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.DictField)
|
|
|
|
def convert_serializer_field_to_dict(field):
|
|
|
|
return DictType
|
2017-06-26 16:28:03 +03:00
|
|
|
|
|
|
|
|
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.JSONField)
|
|
|
|
def convert_serializer_field_to_jsonstring(field):
|
|
|
|
return graphene.types.json.JSONString
|
2017-06-26 16:32:57 +03:00
|
|
|
|
|
|
|
|
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.MultipleChoiceField)
|
2019-09-22 23:13:12 +03:00
|
|
|
def convert_serializer_field_to_list_of_enum(field):
|
|
|
|
child_type = convert_serializer_field_to_enum(field)
|
|
|
|
return (graphene.List, child_type)
|
|
|
|
|
|
|
|
|
|
|
|
@get_graphene_type_from_serializer_field.register(serializers.ChoiceField)
|
|
|
|
def convert_serializer_field_to_enum(field):
|
|
|
|
# enums require a name
|
|
|
|
name = field.field_name or field.source or "Choices"
|
|
|
|
return convert_choices_to_named_enum_with_descriptions(name, field.choices)
|