Оптимизировать сохранение большого количества связанных моделей Django M2M

Пишу приложение, в котором необходимо парсить XML документ с большим количеством вложенностей. Задача: В документе имеется информация о пяти точек измерения, в которых имеется 5 уникальных каналов, с 48 периодами измерений. Реализовать костылями это можно, но происходит 1600 транзакций, это очень плохо. Подскажите, как можно улучшить код:

ViewSet сохранения данных:

class MessageViewSet(viewsets.ModelViewSet):
serializer_class = MessageSerializer
queryset = Message.objects.all()
parser_classes = [MeasuringXmlParse, ]

def create(self, request, *args, **kwargs):
    data = request.data['message']
    area = Area.objects.create(name=data['area']['name'].encode("cp1251").decode('utf-8'),
                               inn=data['area']['inn'].encode("cp1251").decode('utf-8'))

    for point in data['area']['measuringpoint']:  # Получаем одну точку из списка точек

        point_obj = Points.objects.create(name=point['@name'].encode("cp1251").decode('utf-8'), code=point['@code'].encode("cp1251").decode('utf-8'))  # Создаем объект точки

        for channel in point['measuringchannel']:  # Получаем канал в точке

            channel_obj = Channels.objects.create(
                code=channel['@code'].encode("cp1251").decode('utf-8'),  # Создаем один канал для точки
                desc=channel['@desc'].encode("cp1251").decode('utf-8')
            )

            period_obj = Period.objects.bulk_create([Period(
                start=period['@start'].encode("cp1251").decode('utf-8'),
                end=period['@end'].encode("cp1251").decode('utf-8'),  # Создаем список периодов для канала
                value=period['value']) for period in channel['period']])

            for i in period_obj:
                ChannelsPeriod.objects.create(channel=channel_obj, period=i)
                channel_obj.period.add(i)  # Добавляем список периодов в канал

            point_obj.channels.add(channel_obj)

        area.points.add(point_obj)

    message = Message.objects.create(
        message_class=data['@class'].encode("cp1251").decode('utf-8'),
        message_version=data['@version'].encode("cp1251").decode('utf-8'),
        message_number=data['@number'].encode("cp1251").decode('utf-8'),
        datetime=datetime.strptime(str(data['datetime']['timestamp']), '%Y%m%d%H%M%S'),
        day=datetime.strptime(str(data['datetime']['day']), '%Y%m%d'),
        sender_name=data['sender']['name'].encode("cp1251").decode('utf-8'),
        sender_code=data['sender']['inn'].encode("cp1251").decode('utf-8'),
        area=area)

    serializer = MessageSerializer(message)

    return Response(serializer.data)

models.py:

class Message(models.Model):
message_class = models.CharField(max_length=6)
message_version = models.CharField(max_length=2)
message_number = models.CharField(max_length=4)
sender_name = models.CharField(max_length=255, null=True, verbose_name='Sender name')
sender_code = models.CharField(max_length=20, null=True, verbose_name='Sender code')
area = models.ForeignKey('Area', on_delete=models.CASCADE, verbose_name='Area')
datetime = models.DateTimeField()
day = models.CharField(max_length=20)

class Meta:
    verbose_name = 'Message'
    verbose_name_plural = 'Messages'

def __str__(self):
    return f'{self.area}'


class Period(models.Model):
     start = models.CharField(max_length=4, verbose_name='Start measuring')
     end = models.CharField(max_length=4, verbose_name='End measuring')
     value = models.IntegerField(verbose_name='Indication')

def __str__(self):
    return f'{self.start} - {self.end}'

class Meta:
    verbose_name = 'Period'
    verbose_name_plural = 'Periods'
    ordering = ('start',)

class ChannelsPeriod(models.Model):
    channel = models.ForeignKey('Channels', on_delete=models.CASCADE)
    period = models.ForeignKey(Period, on_delete=models.CASCADE)

class Channels(models.Model):
    code = models.CharField(max_length=3, db_index=True, verbose_name='Channel code')
    desc = models.CharField(max_length=50, verbose_name='Description')
    period = models.ManyToManyField(Period, through=ChannelsPeriod)

    def __str__(self):
        return f'{self.desc}'

    class Meta:
       verbose_name = 'Measuring channel'
       verbose_name_plural = 'Measuring channels'
       ordering = ('code',)

class Points(models.Model):
    code = models.CharField(max_length=15, db_index=True, verbose_name='Point code')
    name = models.CharField(max_length=255, db_index=True, verbose_name='Point name')
    channels = models.ManyToManyField(Channels)

    def __str__(self):
        return f'{self.name} - {self.code}'

    class Meta:
        verbose_name = 'Measuring point'
        verbose_name_plural = 'Measuring points'
        ordering = ('code',)

class Area(models.Model):
    name = models.CharField(max_length=255, db_index=True, verbose_name='Area name')
    inn = models.CharField(max_length=10, verbose_name='Area code')
    points = models.ManyToManyField(Points)

    def __str__(self):
        return f'{self.name} - {self.inn}'

    class Meta:
        verbose_name = 'Area'
        verbose_name_plural = 'Areas'
        ordering = ('name',)

Я очень маленький масленок, и не знаю тонкостей работы с большими запросами. Прошу помощи.

XML файл для парсинга

Вернуться на верх