Skip to content

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"}]