Last active
February 16, 2024 10:38
-
-
Save Ruslan-Skira/f4d370af1c35d6d0c1554fa3487a8d50 to your computer and use it in GitHub Desktop.
If data has not the same keys and they are with dots in names i customized the to_internal_value function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""serializers""" | |
import logging | |
from collections import Mapping, OrderedDict | |
from typing import Dict | |
from django.core.exceptions import ValidationError as DjangoValidationError | |
from rest_framework import serializers | |
from rest_framework.exceptions import ValidationError | |
from rest_framework.fields import get_error_detail, set_value, SkipField | |
from rest_framework.settings import api_settings | |
from pricefetch.models import CurrencyExchangeRate # Your model | |
logger = logging.getLogger(__name__) | |
class CurrencyExchangeRateSerializer(serializers.Serializer): | |
""" | |
Base serializer for Alphavantage api. | |
""" | |
from_currency_code = serializers.CharField(max_length=10) | |
from_currency_name = serializers.CharField(max_length=50) | |
to_currency_code = serializers.CharField(max_length=10) | |
to_currency_name = serializers.CharField(max_length=50) | |
exchange_rate = serializers.DecimalField(max_digits=20, decimal_places=10) | |
last_refreshed = serializers.DateTimeField() | |
time_zone = serializers.CharField(max_length=10) | |
bid_price = serializers.DecimalField(max_digits=20, decimal_places=10) | |
ask_price = serializers.DecimalField(max_digits=20, decimal_places=10) | |
def to_internal_value(self, data: Dict): | |
""" | |
Rewriting base function for mapping alphavantage dict keys and model fields. | |
""" | |
mapping_dict = { | |
'from_currency_code': '1. From_Currency Code', | |
'from_currency_name': '2. From_Currency Name', | |
'to_currency_code': '3. To_Currency Code', | |
'to_currency_name': '4. To_Currency Name', | |
'exchange_rate': '5. Exchange Rate', | |
'last_refreshed': '6. Last Refreshed', | |
'time_zone': '7. Time Zone', | |
'bid_price': '8. Bid Price', | |
'ask_price': '9. Ask Price' | |
} | |
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 = data.get(mapping_dict[field.field_name]) # here is mapping model keys with alphavantage api | |
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: | |
set_value(ret, [field.field_name], validated_value) # set_value takes keys in list. | |
if errors: | |
raise ValidationError(errors) | |
return ret | |
def create(self, validated_data: Dict) -> CurrencyExchangeRate: | |
""" | |
Saving model instance. | |
:param validated_data: | |
:type validated_data: | |
:return: | |
:rtype: | |
""" | |
return CurrencyExchangeRate.objects.create(**validated_data) | |
""" | |
Example of using serializer with not matching keys in data. | |
>>> class D(serializers.Serializer): | |
... name = serializers.CharField(max_length=20, source='wtf1 wtf2 wtf3') | |
... sername = serializers.CharField(max_length=12) | |
data = {'wtf1 wtf2 wtf3': "here is", 'sername': 'Hello'} | |
>>> serializer = D(data) | |
>>> serializer_main = D(data=serializer.data) | |
>>> serializer_main.is_valid() | |
True | |
>>> serializer_main.data | |
{'name': 'here is'} | |
Example of using serializer with key where you have dot | |
data = {'wtf1 wtf2. wtf3': "here is"} | |
>>> class D(serializers.Serializer): | |
... name = serializers.CharField(max_length=20, source='wtf1 wtf2. wtf3') | |
... sername = serializers.CharField(max_length=12) | |
... | |
>>> serializer = D(data) | |
>>> serializer.data | |
Traceback (most recent call last): | |
File "/home/user/PycharmProjects/pricefetch/.venv/lib/python3.8/site-packages/rest_framework/fields.py", line 457, in get_attribute | |
return get_attribute(instance, self.source_attrs) | |
File "/home/user/PycharmProjects/pricefetch/.venv/lib/python3.8/site-packages/rest_framework/fields.py", line 95, in get_attribute | |
instance = instance[attr] | |
KeyError: 'wtf1 wtf2' | |
During handling of the above exception, another exception occurred: | |
Traceback (most recent call last): | |
File "<console>", line 1, in <module> | |
File "/home/user/PycharmProjects/pricefetch/.venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 548, in data | |
ret = super().data | |
File "/home/user/PycharmProjects/pricefetch/.venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 246, in data | |
self._data = self.to_representation(self.instance) | |
File "/home/user/PycharmProjects/pricefetch/.venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 502, in to_representation | |
attribute = field.get_attribute(instance) | |
File "/home/user/PycharmProjects/pricefetch/.venv/lib/python3.8/site-packages/rest_framework/fields.py", line 490, in get_attribute | |
raise type(exc)(msg) | |
KeyError: "Got KeyError when attempting to get a value for field `name` on serializer `D`.\nThe serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.\nOriginal exception text was: 'wtf1 wtf2'." | |
Because source attributes are parsed by dot | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment