167 lines
6.5 KiB
Python
167 lines
6.5 KiB
Python
from rest_framework import viewsets, filters
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from rest_framework.pagination import PageNumberPagination
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
|
from django.db.models import Q, Prefetch
|
|
from .models import CaseStudy, CaseStudyCategory, Client, CaseStudyImage, CaseStudyProcess
|
|
from .serializers import (
|
|
CaseStudyListSerializer,
|
|
CaseStudyDetailSerializer,
|
|
CaseStudyCategorySerializer,
|
|
ClientSerializer
|
|
)
|
|
|
|
|
|
class CaseStudyPagination(PageNumberPagination):
|
|
"""Custom pagination for case studies"""
|
|
page_size = 9
|
|
page_size_query_param = 'page_size'
|
|
max_page_size = 100
|
|
|
|
|
|
class CaseStudyViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""
|
|
ViewSet for case studies
|
|
Supports filtering by category, client, and search
|
|
"""
|
|
queryset = CaseStudy.objects.filter(published=True)
|
|
pagination_class = CaseStudyPagination
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
filterset_fields = ['category__slug', 'client', 'featured']
|
|
search_fields = ['title', 'description', 'excerpt']
|
|
ordering_fields = ['published_at', 'views_count', 'created_at', 'display_order']
|
|
ordering = ['display_order', '-published_at']
|
|
lookup_field = 'slug'
|
|
|
|
def get_serializer_class(self):
|
|
if self.action == 'retrieve':
|
|
return CaseStudyDetailSerializer
|
|
return CaseStudyListSerializer
|
|
|
|
def get_queryset(self):
|
|
queryset = super().get_queryset()
|
|
|
|
# Always optimize foreign key lookups
|
|
queryset = queryset.select_related('category', 'client')
|
|
|
|
# Don't add prefetch_related here for retrieve action - it's handled in retrieve() method
|
|
# to avoid duplicate prefetch lookups
|
|
|
|
# Filter by category
|
|
category_slug = self.request.query_params.get('category', None)
|
|
if category_slug and category_slug != 'all':
|
|
queryset = queryset.filter(category__slug=category_slug)
|
|
|
|
# Filter by client
|
|
client_slug = self.request.query_params.get('client', None)
|
|
if client_slug:
|
|
queryset = queryset.filter(client__slug=client_slug)
|
|
|
|
# Search query
|
|
search = self.request.query_params.get('search', None)
|
|
if search:
|
|
queryset = queryset.filter(
|
|
Q(title__icontains=search) |
|
|
Q(description__icontains=search) |
|
|
Q(excerpt__icontains=search)
|
|
)
|
|
|
|
return queryset.distinct()
|
|
|
|
def retrieve(self, request, *args, **kwargs):
|
|
"""Override retrieve to increment view count and ensure optimized queryset"""
|
|
# Get the base queryset (without prefetch_related to avoid duplicates)
|
|
queryset = self.filter_queryset(self.get_queryset())
|
|
|
|
# Now add prefetch_related for detail view optimization
|
|
queryset = queryset.prefetch_related(
|
|
Prefetch(
|
|
'gallery_images',
|
|
queryset=CaseStudyImage.objects.order_by('display_order', 'created_at')
|
|
),
|
|
Prefetch(
|
|
'process_steps',
|
|
queryset=CaseStudyProcess.objects.order_by('step_number')
|
|
)
|
|
)
|
|
|
|
# Get the object using the optimized queryset
|
|
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
|
|
filter_kwargs = {self.lookup_field: kwargs[lookup_url_kwarg]}
|
|
instance = queryset.get(**filter_kwargs)
|
|
|
|
# Increment view count
|
|
instance.increment_views()
|
|
|
|
# Serialize and return
|
|
serializer = self.get_serializer(instance)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def featured(self, request):
|
|
"""Get featured case studies"""
|
|
featured_case_studies = self.get_queryset().filter(featured=True)[:6]
|
|
serializer = self.get_serializer(featured_case_studies, many=True)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def latest(self, request):
|
|
"""Get latest case studies"""
|
|
limit = int(request.query_params.get('limit', 6))
|
|
latest_case_studies = self.get_queryset()[:limit]
|
|
serializer = self.get_serializer(latest_case_studies, many=True)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def popular(self, request):
|
|
"""Get popular case studies by views"""
|
|
limit = int(request.query_params.get('limit', 6))
|
|
popular_case_studies = self.get_queryset().order_by('-views_count')[:limit]
|
|
serializer = self.get_serializer(popular_case_studies, many=True)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def related(self, request, slug=None):
|
|
"""Get related case studies for a specific case study"""
|
|
case_study = self.get_object()
|
|
related_case_studies = self.get_queryset().filter(
|
|
category=case_study.category
|
|
).exclude(id=case_study.id)[:4]
|
|
serializer = self.get_serializer(related_case_studies, many=True)
|
|
return Response(serializer.data)
|
|
|
|
|
|
class CaseStudyCategoryViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""ViewSet for case study categories"""
|
|
queryset = CaseStudyCategory.objects.filter(is_active=True)
|
|
serializer_class = CaseStudyCategorySerializer
|
|
lookup_field = 'slug'
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def with_case_studies(self, request):
|
|
"""Get categories that have published case studies"""
|
|
categories = self.get_queryset().filter(case_studies__published=True).distinct()
|
|
serializer = self.get_serializer(categories, many=True)
|
|
return Response(serializer.data)
|
|
|
|
|
|
class ClientViewSet(viewsets.ReadOnlyModelViewSet):
|
|
"""ViewSet for clients"""
|
|
queryset = Client.objects.filter(is_active=True)
|
|
serializer_class = ClientSerializer
|
|
lookup_field = 'slug'
|
|
|
|
@action(detail=True, methods=['get'])
|
|
def case_studies(self, request, slug=None):
|
|
"""Get all case studies for a specific client"""
|
|
client = self.get_object()
|
|
case_studies = CaseStudy.objects.filter(client=client, published=True)
|
|
page = self.paginate_queryset(case_studies)
|
|
if page is not None:
|
|
serializer = CaseStudyListSerializer(page, many=True)
|
|
return self.get_paginated_response(serializer.data)
|
|
serializer = CaseStudyListSerializer(case_studies, many=True)
|
|
return Response(serializer.data)
|
|
|