Оптимизировать сохранение большого количества связанных моделей 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',)
Я очень маленький масленок, и не знаю тонкостей работы с большими запросами. Прошу помощи.