Оптимизация вложенных сериализаторов DRF
Помогите, плиз, оптимизировать чудовищный код в сериализаторе, который очень медленно работает... Как я понимаю, основная проблема в нескольких SerializerMethodFields, где вызываются get_tasks (). Подскажите, пожалуйста, как правильно сделать здесь - в init загрузить все задачи, которые есть в self.tasks. А в методе to_representation все 4 ключа вызова SerializerMethodField - equipment_types, recovery_days, completed_days, work_in_progress_days? И самое главное - как правильно оптимизировать вызов вложенных сериализаторов?
Самое главное - как правильно оптимизировать вызов вложенных сериализаторов?
Вот некоторые предложения по оптимизации кода в вашем сериализаторе:
Предварительно загрузите все задачи экземпляра MonthPlan в метод init MonthPlanViewSerializer, а не вызывайте метод get_tasks для каждого поля SerializerMethodField. Это позволит избежать ненужных запросов к базе данных для каждого поля.
В методе to_representation вызовите соответствующий метод для каждого поля SerializerMethodField (например, get_recovery_days) и сохраните результат в локальной переменной, а не вызывайте метод несколько раз.
Для вложенных сериализаторов (например, EquipmentTypeSerializer) можно использовать метод prefetch_related для предварительной загрузки связанных объектов при запросе к базе данных. Это может повысить производительность за счет уменьшения количества запросов к базе данных, необходимых для сериализации данных. Вот пример того, как вы можете применить эти предложения в своем коде:
class MonthPlanViewSerializer(serializers.HyperlinkedModelSerializer):
year_plan_id = serializers.PrimaryKeyRelatedField(
queryset=YearPlan.objects.all(),
source='year_plan.id'
)
equipment_id = serializers.PrimaryKeyRelatedField(
queryset=Equipment.objects.all(),
source='equipment.id',
required=False
)
equipment = EquipmentSerializer(many=False, read_only=True)
transport_id = serializers.PrimaryKeyRelatedField(
queryset=Transport.objects.all(),
source='transport.id',
default=None
)
transport = TransportSerializer(many=False, read_only=True)
equipment_types = serializers.SerializerMethodField()
tasks = SimpleTaskSerializer(many=True, read_only=True)
recovery_days = serializers.SerializerMethodField()
completed_days = serializers.SerializerMethodField()
work_in_progress_days = serializers.SerializerMethodField()
# Preload all tasks for the MonthPlan instance in the __init__ method
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tasks = self.instance.tasks.all()
# Return the preloaded tasks
def get_tasks(self, instance: MonthPlan):
return self.tasks
def get_work_in_progress_days(self, instance: MonthPlan) -> set:
tasks = self.get_tasks(instance)
return set(int(task.planned_date.strftime("%d")) for task in tasks if task.work_in_progress)
def get_completed_days(self, instance: MonthPlan) -> list:
return self.get_common_days(instance, 'is_completed')
def get_recovery_days(self, instance: MonthPlan) -> list:
return self.get_common_days(instance, 'is_broken')