ListSerializer и Foreign Key, is_valid при выполнении N+1 запроса

Я пытаюсь улучшить свой сериализатор, чтобы иметь возможность создавать несколько объектов с минимальными запросами. Поэтому я реализовал ListSerializer, который будет массово создавать объекты вместо вызова save для каждого объекта.

Вот мой текущий код:

class GatewayTechnicalLogListSerializer(serializers.ListSerializer):
    gateway = serializers.IntegerField(required=True)


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.gateways_ids: dict = {}
        for gat_tech_log in self.initial_data:
            self.gateways_ids[gat_tech_log['gateway']] = True
        self.gateways_ids = Gateway.objects.filter(
            id__in=self.gateways_ids.keys()
        ).only('id').values_list('id', flat=True)


    def validate(self, attrs):
        if attrs.gateway not in self.gateways_ids.keys():
            raise serializers.ValidationError('Gateway does not exists.')
        return attrs


    def create(self, validated_data):
        gw_tech_logs_o = [GatewayTechnicalLog(**item) for item in validated_data]
        res = GatewayTechnicalLog.objects.bulk_create(gw_tech_logs_o)
        return res


class GatewayTechnicalLogSerializer(serializers.ModelSerializer):
    class Meta:
        model = GatewayTechnicalLog
        fields = '__all__'
        list_serializer_class = GatewayTechnicalLogListSerializer

Моя проблема в том, что когда вызывается метод is_valid, он пытается проверить шлюз внешнего ключа для каждого объекта и таким образом получает связанный внешний ключ.

Я пытаюсь удалить валидацию этого поля и проверить его самостоятельно, но это ничего не меняет...

Я не нашел ни одного примера этого, есть идеи?

Спасибо!

Ок, так что я закончил тем, что сделал, я не уверен, что это лучший подход, но он, кажется, работает:

class GatewayTechnicalLogListSerializer(serializers.ListSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.gateways_ids: dict = {}
        for gw_tech_log in self.initial_data:
            self.gateways_ids[gw_tech_log['gateway']] = True
        self.gateways_o = Gateway.objects.filter(
            id__in=self.gateways_ids.keys()
        )
        self.gateways_ids = list(self.gateways_o.values_list('id', flat=True))


    def validate(self, attrs):
        # Validating because validation was removed
        for gw_tech_log in attrs:
            if gw_tech_log['gateway'] not in self.gateways_ids:
                raise serializers.ValidationError('Gateway does not exists.')
        return attrs


    def create(self, validated_data):
        # Bulk creating and logging after into Azure to improve performance
        gw_tech_logs_o: list = []
        for item in validated_data:
            gateway_id: int = item.pop('gateway')
            item['gateway'] = next(
                gateway_o for gateway_o in self.gateways_o if gateway_o.id == gateway_id
            )
            gw_tech_logs_o.append(GatewayTechnicalLog(**item))
        res = GatewayTechnicalLog.objects.bulk_create(gw_tech_logs_o)
        return res


class GatewayTechnicalLogSerializer(serializers.ModelSerializer):
    class Meta:
        model = GatewayTechnicalLog
        fields = '__all__'
        list_serializer_class = GatewayTechnicalLogListSerializer


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Removing validation on serializer for gateway field
        self.fields['gateway'] = serializers.IntegerField(required=True)


    def to_representation(self, obj):
        # Rolling back changes on field for representation
        self.fields['gateway'] = serializers.PrimaryKeyRelatedField(required=True, queryset=obj.gateway)
        return super(GatewayTechnicalLogSerializer, self).to_representation(obj)
Вернуться на верх