Files
GNX-WEB/backEnd/services/views.py
Iliyan Angelov 366f28677a update
2025-11-24 03:52:08 +02:00

213 lines
6.6 KiB
Python

from rest_framework import generics, status, filters
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from django_filters.rest_framework import DjangoFilterBackend
from django.shortcuts import get_object_or_404
from django.db.models import Q, Avg
from django.db import models
from django.conf import settings
from .models import Service, ServiceFeature, ServiceCategory
from .serializers import (
ServiceSerializer,
ServiceListSerializer,
ServiceCreateUpdateSerializer,
ServiceFeatureSerializer,
ServiceCategorySerializer
)
class ServiceListView(generics.ListAPIView):
"""
List all active services with optional filtering
"""
queryset = Service.objects.filter(is_active=True)
serializer_class = ServiceListSerializer
permission_classes = [AllowAny]
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['featured', 'display_order']
search_fields = ['title', 'description']
ordering_fields = ['display_order', 'created_at', 'title', 'price']
ordering = ['display_order', 'created_at']
def get_queryset(self):
queryset = super().get_queryset()
# Filter by category if provided
category_slug = self.request.query_params.get('category', None)
if category_slug:
queryset = queryset.filter(category__slug=category_slug)
# Filter by price range if provided
min_price = self.request.query_params.get('min_price', None)
max_price = self.request.query_params.get('max_price', None)
if min_price:
queryset = queryset.filter(price__gte=min_price)
if max_price:
queryset = queryset.filter(price__lte=max_price)
return queryset
class ServiceDetailView(generics.RetrieveAPIView):
"""
Retrieve a single service by slug
"""
queryset = Service.objects.filter(is_active=True)
serializer_class = ServiceSerializer
permission_classes = [AllowAny]
lookup_field = 'slug'
class ServiceCreateView(generics.CreateAPIView):
"""
Create a new service (admin only)
"""
queryset = Service.objects.all()
serializer_class = ServiceCreateUpdateSerializer
permission_classes = [IsAuthenticated]
parser_classes = [MultiPartParser, FormParser, JSONParser]
class ServiceUpdateView(generics.UpdateAPIView):
"""
Update an existing service (admin only)
"""
queryset = Service.objects.all()
serializer_class = ServiceCreateUpdateSerializer
permission_classes = [IsAuthenticated]
lookup_field = 'slug'
parser_classes = [MultiPartParser, FormParser, JSONParser]
class ServiceDeleteView(generics.DestroyAPIView):
"""
Delete a service (admin only)
"""
queryset = Service.objects.all()
permission_classes = [IsAuthenticated]
lookup_field = 'slug'
def perform_destroy(self, instance):
# Delete the image file if it exists
if instance.image:
instance.image.delete(save=False)
instance.delete()
class FeaturedServicesView(generics.ListAPIView):
"""
List all featured services
"""
queryset = Service.objects.filter(is_active=True, featured=True)
serializer_class = ServiceListSerializer
permission_classes = [AllowAny]
ordering = ['display_order', 'created_at']
class ServiceCategoryListView(generics.ListAPIView):
"""
List all active service categories
"""
queryset = ServiceCategory.objects.filter(is_active=True)
serializer_class = ServiceCategorySerializer
permission_classes = [AllowAny]
ordering = ['display_order', 'name']
class ServiceCategoryDetailView(generics.RetrieveAPIView):
"""
Retrieve a single service category by slug
"""
queryset = ServiceCategory.objects.filter(is_active=True)
serializer_class = ServiceCategorySerializer
permission_classes = [AllowAny]
lookup_field = 'slug'
@api_view(['GET'])
@permission_classes([AllowAny])
def service_search(request):
"""
Search services by query string
"""
query = request.GET.get('q', '')
if not query:
return Response({'error': 'Query parameter "q" is required'},
status=status.HTTP_400_BAD_REQUEST)
services = Service.objects.filter(
Q(is_active=True) & (
Q(title__icontains=query) |
Q(description__icontains=query) |
Q(slug__icontains=query)
)
).order_by('display_order', 'created_at')
serializer = ServiceListSerializer(services, many=True)
return Response({
'query': query,
'count': services.count(),
'results': serializer.data
})
@api_view(['GET'])
@permission_classes([AllowAny])
def service_stats(request):
"""
Get service statistics
"""
total_services = Service.objects.filter(is_active=True).count()
featured_services = Service.objects.filter(is_active=True, featured=True).count()
categories = ServiceCategory.objects.filter(is_active=True).count()
# Average price
services_with_price = Service.objects.filter(is_active=True, price__gt=0)
avg_price = services_with_price.aggregate(avg_price=Avg('price'))['avg_price'] or 0
return Response({
'total_services': total_services,
'featured_services': featured_services,
'categories': categories,
'average_price': float(avg_price)
})
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def upload_service_image(request, slug):
"""
Upload an image for a specific service (admin only)
"""
try:
service = get_object_or_404(Service, slug=slug)
if 'image' not in request.FILES:
return Response(
{'error': 'No image file provided'},
status=status.HTTP_400_BAD_REQUEST
)
# Delete old image if it exists
if service.image:
service.image.delete(save=False)
# Save new image
service.image = request.FILES['image']
service.save()
serializer = ServiceSerializer(service)
return Response({
'message': 'Image uploaded successfully',
'service': serializer.data
})
except Exception as e:
return Response(
{'error': f'Failed to upload image: {str(e)}'},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)