Django REST Framework Сериализация POST идет медленно - PullRequest
0 голосов
/ 18 ноября 2018

Я работаю на Django 2.1.1 и Python 3.6.5 и выполняю достаточно большую операцию POST (32 000 объектов JSON). У меня есть следующее:

Модель:

class Data(models.Model):
    investigation = models.ForeignKey(Investigation)
    usage = models.FloatField()
    sector = models.CharField(max_length=100, blank=False, default='')
    cost = models.FloatField()
    demand = models.FloatField()

Serializer:

class DataSerializer(serializers.ModelSerializer):
    class Meta:
        model = Data
        fields = ('investigation', 'usage', 'sector', 'cost', 'demand')

Вид:

class DataView(generics.CreateAPIView):
    def create(self, request, pk, format=None):
        data_serializer = DataSerializer(data=request.data, many=True)
        if data_serializer.is_valid():
            data_serializer.save()

Проблемы возникают при выполнении шагов is_valid () и save (), каждый из которых запускает отдельный запрос для каждого из 32 000 объектов.

Я потратил много времени на изучение этой проблемы, и я предполагаю, что шаг is_valid () является медленным из-за проблемы запроса N + 1, так как внешний ключ ищется каждый раз (хотя я мог бы быть неправильно в этом!) но я понятия не имею, как реализовать метод prefetch_related в этой структуре.

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

Любые указатели будут с благодарностью.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Одним из возможных решений является выполнение Django ORM bulk_create() после проверки данных с использованием вашего сериализатора. Ваш взгляд будет выглядеть примерно так:

class DataView(generics.CreateAPIView):
    def create(self, request, pk, format=None):
        data_serializer = DataSerializer(data=request.data, many=True)
        if data_serializer.is_valid():
            data_objects = []
            for data_object_info in data_serializer.validated_data:
                data_objects.append(Data(**data_object_info))
            Data.objects.bulk_create(data_objects)

или просто следующее, если вам нужен однострочный:

Data.objects.bulk_create([Data(**params) for params in data_serializer.validated_data])

Если вы не хотите загромождать свое представление, вы можете написать класс или метод, который выполняет проверку (с использованием сериализатора) и создание. Затем вы можете использовать это в представлении.

0 голосов
/ 19 ноября 2018

Вы можете попробовать переопределить метод создания сериализатора следующим образом:

def create(self, request):
    is_many = True if isinstance(request.data, list) else False

    serializer = self.get_serializer(data=request.data, many=is_many)
    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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...