Optimize product queries with select_related and prefetch_related for improved performance

This commit is contained in:
Parsa Nazer
2025-11-03 12:25:02 +03:30
parent bf0817ed34
commit 6b4fcb0672
+33 -12
View File
@@ -203,24 +203,32 @@ class AllProductsView(APIView):
def get(self, request): def get(self, request):
try: try:
category_slug = request.query_params.get('category') category_slug = request.query_params.get('category')
products = ProductModel.objects.all()
# Start with optimized base query
products = ProductModel.objects.select_related(
'category',
'category__parent'
).prefetch_related(
'variants__product_attributes__attribute_type',
'variants__images',
)
if category_slug: if category_slug:
if 'category' not in category_slug: if 'category' not in category_slug:
sub_category = get_object_or_404( sub_category = get_object_or_404(
SubCategoryModel, slug=category_slug) SubCategoryModel, slug=category_slug)
products = ProductModel.objects.filter( products = products.filter(category=sub_category)
category=sub_category)
else: else:
main_category = get_object_or_404( main_category = get_object_or_404(
MainCategoryModel, slug=category_slug) MainCategoryModel, slug=category_slug)
sub_categories = main_category.subcategorys.all() sub_categories = main_category.subcategorys.all()
products = ProductModel.objects.filter( products = products.filter(category__in=sub_categories)
category__in=sub_categories)
in_stock = request.query_params.get('in_stock') in_stock = request.query_params.get('in_stock')
if in_stock is not None: if in_stock is not None:
if in_stock.lower() == 'true': if in_stock.lower() == 'true':
products = products.filter(variants__in_stock__gt=0) products = products.filter(
variants__in_stock__gt=0).distinct()
elif in_stock.lower() != 'false': elif in_stock.lower() != 'false':
return Response({'detail': 'in_stock must be "true" or "false".'}, status=status.HTTP_400_BAD_REQUEST) return Response({'detail': 'in_stock must be "true" or "false".'}, status=status.HTTP_400_BAD_REQUEST)
@@ -228,7 +236,8 @@ class AllProductsView(APIView):
has_discount = request.query_params.get('has_discount') has_discount = request.query_params.get('has_discount')
if has_discount is not None: if has_discount is not None:
if has_discount.lower() == 'true': if has_discount.lower() == 'true':
products = products.filter(variants__discount__gt=0) products = products.filter(
variants__discount__gt=0).distinct()
elif has_discount.lower() != 'false': elif has_discount.lower() != 'false':
return Response({'detail': 'has_discount must be "true" or "false".'}, status=status.HTTP_400_BAD_REQUEST) return Response({'detail': 'has_discount must be "true" or "false".'}, status=status.HTTP_400_BAD_REQUEST)
@@ -372,6 +381,16 @@ class ShowCaseProductsView(APIView):
def get(self, request): def get(self, request):
try: try:
category_id = request.query_params.get('slider_category', None) category_id = request.query_params.get('slider_category', None)
# Start with optimized base query
products = ProductModel.objects.select_related(
'category',
'category__parent'
).prefetch_related(
'variants__product_attributes__attribute_type',
'variants__images',
)
if category_id: if category_id:
try: try:
category_id = int(category_id) category_id = int(category_id)
@@ -381,22 +400,22 @@ class ShowCaseProductsView(APIView):
slider_category = get_object_or_404( slider_category = get_object_or_404(
ShowCaseSlider, pk=category_id) ShowCaseSlider, pk=category_id)
products = ProductModel.objects.filter( products = products.filter(
variants__slider_category=slider_category).distinct() variants__slider_category=slider_category).distinct()
else: else:
products = ProductModel.objects.filter( products = products.filter(
variants__slider_category__isnull=False).distinct() variants__slider_category__isnull=False).distinct()
# Filter by stock status if `in_stock` is specified # Filter by stock status if `in_stock` is specified
in_stock = request.query_params.get('in_stock', "false") == 'true' in_stock = request.query_params.get('in_stock', "false") == 'true'
if in_stock: if in_stock:
products = products.filter(variants__in_stock__gt=0) products = products.filter(variants__in_stock__gt=0).distinct()
# Filter by discount if `has_discount` is specified # Filter by discount if `has_discount` is specified
has_discount = request.query_params.get( has_discount = request.query_params.get(
'has_discount', "false") == 'true' 'has_discount', "false") == 'true'
if has_discount: if has_discount:
products = products.filter(variants__discount__gt=0) products = products.filter(variants__discount__gt=0).distinct()
# Search filter # Search filter
search_query = request.query_params.get('search', None) search_query = request.query_params.get('search', None)
@@ -460,8 +479,10 @@ class CommentView(APIView):
) )
def get(self, request, slug): def get(self, request, slug):
product = get_object_or_404(ProductModel, slug=slug) product = get_object_or_404(ProductModel, slug=slug)
# Optimize comments query to prefetch user data
comments = product.comments.filter( comments = product.comments.filter(
review_status__in=['not_reviwed', 'reviewed_and_confirmed']) review_status__in=['not_reviwed', 'reviewed_and_confirmed']
).select_related('user')
paginator = self.pagination_class() paginator = self.pagination_class()
paginated_comments = paginator.paginate_queryset(comments, request) paginated_comments = paginator.paginate_queryset(comments, request)
comments_ser = self.serializer_class( comments_ser = self.serializer_class(