Оптимизация запроса в django
У меня имеются модели, сериализаторы, и вьюшка. Проблема n+1, у меня в бд 5 товаров, но по итогу просходит 7 запросов. Если я уберу метод get_color в сериализаторе, то запросов станет 2, но не будет нужных мне полей. Как сделать нужно, чтобы не было там много запросов.
models.py
class Product(models.Model):
name = models.CharField(max_length=255, unique=True, verbose_name='Название')
description = models.TextField(verbose_name='Описание')
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Цена')
categories = models.ManyToManyField(Category, related_name='products', verbose_name='Категории')
введите сюда код
class ProductColorSize(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name='Товар', related_name='product_color_sizes')
color = models.ForeignKey(Color, on_delete=models.CASCADE, verbose_name='Цвет')
size = models.ForeignKey(Size, on_delete=models.CASCADE, verbose_name='Размер')
serializers.py
... # остальные обычные model сериализаторы
class ProductSerializer(ModelSerializer):
colors = SerializerMethodField()
class Meta:
model = Product
fields = '__all__'
def get_colors(self, obj):
color_sizes = defaultdict(set)
for pcs in obj.product_color_sizes.filter(product=obj).select_related('product', 'color', 'size'):
color_sizes[pcs.color].add(pcs.size.name)
colors = []
for color, sizes in color_sizes.items():
color_data = ColorSerializer(color).data
color_data['available_sizes'] = sorted(list(sizes))
colors.append({"color": color_data})
return colors
views.py
class ProductAPIView(ReadOnlyModelViewSet):
serializer_class = ProductSerializer
queryset = Product.objects.all().prefetch_related(
Prefetch('categories', Category.objects.all().only('id')),
)
filter_backends = [DjangoFilterBackend]
filterset_fields = ['id', 'categories']
Мне необходима следующая структура вывода данных:
[
{
"id": 1,
"colors": [
{
"color": {
"id": 1,
"name": "Белый",
"available_sizes": [
"66",
"80"
]
}
},
{
"color": {
"id": 2,
"name": "Черный",
"available_sizes": [
"80"
]
}
}
],
"name": "Название",
"description": "Описание",
"price": "1000",
"categories": []
},
]