Оптимизация обработки после запроса DRF путем предотвращения полной сериализации ответа - PullRequest
0 голосов
/ 28 октября 2018

Я определил AViewSet и ASerializer для моего AModel:

class AModel(Model):
    name = CharField(16)
    text = TextField()
    related = ForeignField('ARelated')

class AViewSet(ModelViewSet):
    queryset = AModel.objects.all()
    serializer_class = ASerializer

class ASerializer(Serializer):
    class Meta(object):
        model = AModel
        fields = '__all__'

Я написал RESTful-клиент, который отправляет много данных в это представление / конечную точкув нескольких запросах, создавая много AModel записей.Однако я заметил, что значительная часть времени сервера тратится на генерацию ответа , и, немного погуглив, я обнаружил несколько ссылок на опасность вложенных отношений , которая выглядит какПриличное исправление, но заставило меня задуматься:

Я уже знаю, что я написал, и мне не нужны pk s, так что я могу предотвратить этот ответ сериализации полностью?Могу ли я вместо этого просто сериализовать количество вставленных строк?

Взглянув на класс CreateModelMixin DRF:

class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

Я понял, что могу переопределить метод create и переопределить его безвозвращая serializer.data как часть ответа, так что это будет выглядеть примерно так:

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response({}, status=status.HTTP_201_CREATED, headers=headers)

У меня есть два вопроса относительно этого подхода:

  1. Имеет ли эта практикаПредотвращение полной сериализации объектов, созданных с помощью POST, имеет смысл в отношении шаблонов проектирования RESTful, подхода, идеологии и т. д.
  2. Будет ли это на самом деле select исключать все связанные данные (а также выполнять любые SerializerMethodFieldи т. д.

1 Ответ

0 голосов
/ 28 октября 2018

Давайте возьмем базовую комбинацию ModelViewset и ModelSerializer здесь :) Это будет похоже на

# serializers.py
class SampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = SampleModel
        fields = '__all__'

# views.py
class SampleViewset(viewsets.ModelViewSet):
    queryset = SampleModel.objects.all()
    serializer_class = SampleSerializer

Почему DRF возвращает все данные обратно клиенту?
Здесь SampleViewset использует SampleSerializer каждый раз, и он будет сериализован все поля , определенные в классе сериализатора.Согласно текущей конфигурации

Какое возможное решение?
Возможное решение для этого - остановить процесс сериализации некоторых полей некоторыми способами :)

Как это сделать?
Насколько я знал, это можно сделать двумя способами.
1. Использовать минимальный класс SampleSerializer для метода POST
2. переопределить to_representation() метод SampleSerializer для POST запросов

Метод-1: использовать другой сериализатор
Определитьновый класс сериализатора с полями, которые вы хотите отправлять и получать, в то время как POST запрос

class SampleSerializerMinimal(serializers.ModelSerializer):
    class Meta:
        model = SampleModel
        fields = ('id', 'name', 'age')

Теперь мы должны указать наборам просмотра использовать этоСериализатор для методов POST, это можно сделать в get_serializer_class() набора

class SampleViewset(viewsets.ModelViewSet):
    queryset = SampleModel.objects.all()
    serializer_class = SampleSerializer

    <b>def get_serializer_class(self):
        if self.request.method == 'POST':
            return SampleSerializerMinimal
        return SampleSerializer</b>



Метод 2: Переопределить метод to_representation()

class SampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = SampleModel
        fields = '__all__'

    <b>def to_representation(self, instance):
        try:
            if self.context['view'].request.method == 'POST':
                return {
                    "id": instance.id,
                    "name": instance.name,
                    "age": instance.age
                }
        except KeyError:
            return super(SampleSerializer, self).to_representation(instance)
        return super(SampleSerializer, self).to_representation(instance)</b>



Как лучше?
Я чувствовал Метод-1 - это более подходящий способ работы, но вы можетеНе добавляйте id только к fields, потому что для запроса POST может потребоваться больше полей.
Method-2 тоже хорошо, но не так многоочистить, если вы хотите вернуть n поля и записать его в своем to_representation() методе


UPDATE-1
Метод 3: комбинация method-1 и method-2

# serializer.py
class <b>SampleSerializerMinimal</b>(serializers.ModelSerializer):
    class Meta:
        model = SampleModel
        fields = ('id', 'name', 'age')

    <b>def to_representation(self, instance):
        """
        we don't have to check the request method, because DRF routing only POSt requests to this serializer
        """
        return {"id": instance.id}</b>


# views.py
class SampleViewset(viewsets.ModelViewSet):
    queryset = SampleModel.objects.all()
    serializer_class = SampleSerializer

    <b>def get_serializer_class(self):
        if self.action.method == 'POST':
            return SampleSerializerMinimal
        return SampleSerializer</b>



ОБНОВЛЕНИЕ-2

Имеет ли смысл такая практика предотвращения полной сериализации объектов, созданных с помощью POST, в отношении шаблонов проектирования RESTful, подхода, идеологии и т. Д.?

.data вызывает to_representation() метод, который вызывает связанные объекты и все другие поля в сериализаторе .( Исходный код свойства data сериализатора ) Так что, если вы можете избежать этого вызова .data, было бы неплохо!.
Поскольку я видел много ответов API с единственной детализацией, такой как {"status":true} после запроса POST, я не думаю, что ваш подход излишне убивает шаблоны DRF и другие вещи

Действительно ли это позволит избежать выбора всех связанных данных (а также выполнения каких-либо SerializerMethodFields и т. Д.?

Да. Как я уже говорил выше, этоне будет вызывать процесс сериализации, пока не будет вызван .data

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...