Serializer choicer api reference
Если вам необходимо выбирать input сериалайзер исходя из входных данных или выбирать output сериалайзер исходя из данных, полученных в процессе выполнения view функции (то есть ваши входные/выходные данные полиморфны), то вам необходимо написать собственный choicer - класс, который содержит в себе логику сериалайзера в зависимости от входных/выходных данных.
Ниже представлен абстрактный класс:
class SerializerChoicerBase(Generic[*SerializerTypeList], ABC):
def __init__(self, *serializers_list: *Type[SerializerTypeList]):
self.serializers_list = serializers_list
@abstractmethod
def get_base_data(self, external_data):
pass
@abstractmethod
def get_serializer_class(self, base_data):
pass
@abstractmethod
def get_serializer_kwargs(self, base_data) -> dict: # usually is many kwargs
pass
def __call__(self, external_data, **kwargs): # -> Type[*SerializerTypeList]:
base_data = self.get_base_data(external_data)
sr = self.get_serializer_class(base_data)
sr_kwargs = self.get_serializer_kwargs(base_data)
return sr(**kwargs, **sr_kwargs)
Вам нужно наследоваться от него и реализовать 3 метода:
-
get_base_data - метод для подготовки входных внешних данных (request/response в частности)
-
get_serializer_class - метод, который возвращает класс сериалайзера из общего списка сериалайзеров, исходя из входных данных.
-
get_serializer_kwargs - метод, который возвращает kwargs, которые передадутся в сериалайзер при его вызове исходя из входных данных (в большинстве случаев будет использоваться для many и context kwargs)
Ниже представлен пример реализации choicer, который работает следующим образом:
-
get_base_data: Извлекает из request.data (request body) значение ключа "sr_name", если ключа не существует извлекает None.
-
get_serializer_class: проходится по всем переданным в него при аннотации сериалайзерам, смотрит есть ли в низ атрибут Meta, если есть смотрит есть ли у объекта Meta атрибут name, если находит сериалайзер, у которого атрибут name в классе Meta соответствует sr_name, возвращает сериалайзер, иначе
ValidationError('Serializer not found')
-
get_serializer_kwargs: возвращает пустой словарь.
from advantage.drf.serializer_choicer import SerializerChoicerBase, SerializerTypeList
from advantage.drf.views import SmartApiView
from rest_framework import serializers
class BodyChoicer(SerializerChoicerBase[SerializerTypeList]):
def get_base_data(self, external_data):
sr_name = external_data.data.pop("sr_name", None)
return sr_name
def get_serializer_class(self, base_data):
for sr in self.serializers_list:
meta = getattr(sr, 'Meta', None)
sr_name = getattr(meta, 'name', None)
if base_data == sr_name:
return sr
raise ValidationError('Serializer not found')
def get_serializer_kwargs(self, base_data) -> dict:
return {}
class TestInputBodySerializer(serializers.Serializer):
count = serializers.IntegerField()
class Meta:
name = 'count'
class TestInputBodySerializer2(serializers.Serializer):
value = serializers.FloatField()
class Meta:
name = 'value'
class TestSmartApiView(SmartApiView):
def post(self,
request: Request,
body: BodyChoicer[TestInputBodySerializer, TestInputBodySerializer2]) -> List[TestOutputQSSerializer]:
print(body.validated_data)
return [{'data': "is dict"}]