Skip to content

Instantly share code, notes, and snippets.

@JPDSousa
Created December 6, 2022 16:10
Show Gist options
  • Save JPDSousa/794029d18e18e2851ca4483ba2054d29 to your computer and use it in GitHub Desktop.
Save JPDSousa/794029d18e18e2851ca4483ba2054d29 to your computer and use it in GitHub Desktop.
from collections import OrderedDict
from typing import Dict, Any, Mapping
from django.core.exceptions import ValidationError as DjangoValidationError
from rest_framework import serializers
from rest_framework.fields import set_value, get_error_detail, SkipField
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings
class SetValueOverrideSerializerMixin(serializers.Serializer):
"""
Copies serializers.Serializer.to_internal_value, making set_value overridable.
No functional changes introduced when compared to serializers.Serializer.
"""
def set_value(self, aggregator: Dict[str, Any], field: serializers.Field, validated_value: Any):
set_value(aggregator, field.source_attrs, validated_value)
def to_internal_value(self, data):
"""Original implementation, except for the comment-wrapped part below."""
if not isinstance(data, Mapping):
message = self.error_messages['invalid'].format(datatype=type(data).__name__)
raise ValidationError({api_settings.NON_FIELD_ERRORS_KEY: [message]}, code='invalid')
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
###########################################
# NB: Beginning of the added functionality
self.set_value(ret, field, validated_value)
# NB: End of the added functionality
###########################################
if errors:
raise ValidationError(errors)
return ret
class RegroupSerializerMixin(SetValueOverrideSerializerMixin):
def set_value(self, aggregator: Dict[str, Any], field: serializers.Field, validated_value: Any):
"""
Uses deep_update to update aggregator with the validated_value, in case it is a mapping.
"""
if isinstance(validated_value, Mapping):
materialized_dict = {}
set_value(materialized_dict, field.source_attrs, validated_value)
#https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth
aggregator.update(deep_update(aggregator, materialized_dict))
else:
super().set_value(aggregator, field, validated_value)
@JPDSousa
Copy link
Author

That might count as a golden vote than 😅

@auvipy
Copy link

auvipy commented Dec 14, 2022

it will actually take some time. see what I commented there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment