from rest_framework import viewsets, status, filters from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly from django_filters.rest_framework import DjangoFilterBackend from django.db.models import Q, Avg, Count from django.shortcuts import get_object_or_404 from .models import Product, Category, Review, Wishlist, GalleryImage, CustomOrder from .serializers import ( ProductSerializer, ProductListSerializer, ProductDetailSerializer, CategorySerializer, ReviewSerializer, WishlistSerializer, CustomOrderSerializer, CartSerializer, SearchFilterSerializer, ProductStatsSerializer, GalleryImageDetailSerializer ) class ProductViewSet(viewsets.ModelViewSet): """ViewSet für Produkt-API""" queryset = Product.objects.select_related('category').prefetch_related( 'reviews', 'gallery_images', 'wishlists' ).all() serializer_class = ProductListSerializer permission_classes = [IsAuthenticatedOrReadOnly] filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_fields = ['category', 'product_type', 'fursuit_type', 'style', 'on_sale', 'is_featured'] search_fields = ['name', 'description'] ordering_fields = ['name', 'base_price', 'created_at', 'average_rating'] ordering = ['-created_at'] def get_serializer_class(self): if self.action == 'retrieve': return ProductDetailSerializer elif self.action == 'create' or self.action == 'update': return ProductSerializer return ProductListSerializer def get_queryset(self): queryset = super().get_queryset() # Filter nach Preis min_price = self.request.query_params.get('min_price') max_price = self.request.query_params.get('max_price') if min_price: queryset = queryset.filter(base_price__gte=min_price) if max_price: queryset = queryset.filter(base_price__lte=max_price) # Filter nach Lagerbestand in_stock = self.request.query_params.get('in_stock') if in_stock == 'true': queryset = queryset.filter(stock__gt=0) return queryset @action(detail=False, methods=['get']) def featured(self, request): """Featured Produkte""" products = self.get_queryset().filter(is_featured=True) serializer = self.get_serializer(products, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def on_sale(self, request): """Produkte im Angebot""" products = self.get_queryset().filter(on_sale=True) serializer = self.get_serializer(products, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def low_stock(self, request): """Produkte mit niedrigem Lagerbestand""" products = self.get_queryset().filter(stock__lte=5, stock__gt=0) serializer = self.get_serializer(products, many=True) return Response(serializer.data) @action(detail=True, methods=['post']) def add_to_wishlist(self, request, pk=None): """Produkt zur Wunschliste hinzufügen""" product = self.get_object() user = request.user if not user.is_authenticated: return Response( {'error': 'Authentication required'}, status=status.HTTP_401_UNAUTHORIZED ) wishlist, created = Wishlist.objects.get_or_create(user=user) wishlist.products.add(product) return Response({ 'message': 'Product added to wishlist', 'product_id': product.id }) @action(detail=True, methods=['post']) def remove_from_wishlist(self, request, pk=None): """Produkt von Wunschliste entfernen""" product = self.get_object() user = request.user if not user.is_authenticated: return Response( {'error': 'Authentication required'}, status=status.HTTP_401_UNAUTHORIZED ) try: wishlist = Wishlist.objects.get(user=user) wishlist.products.remove(product) return Response({ 'message': 'Product removed from wishlist', 'product_id': product.id }) except Wishlist.DoesNotExist: return Response( {'error': 'Wishlist not found'}, status=status.HTTP_404_NOT_FOUND ) @action(detail=False, methods=['get']) def stats(self, request): """Produkt-Statistiken""" queryset = self.get_queryset() stats = { 'total_products': queryset.count(), 'featured_products': queryset.filter(is_featured=True).count(), 'on_sale_products': queryset.filter(on_sale=True).count(), 'low_stock_products': queryset.filter(stock__lte=5, stock__gt=0).count(), 'categories_count': Category.objects.count(), 'average_rating': queryset.aggregate(Avg('average_rating'))['average_rating__avg'] or 0, 'total_reviews': Review.objects.count(), } serializer = ProductStatsSerializer(stats) return Response(serializer.data) class CategoryViewSet(viewsets.ReadOnlyModelViewSet): """ViewSet für Kategorie-API""" queryset = Category.objects.prefetch_related('products').all() serializer_class = CategorySerializer permission_classes = [IsAuthenticatedOrReadOnly] @action(detail=True, methods=['get']) def products(self, request, pk=None): """Produkte einer Kategorie""" category = self.get_object() products = category.products.all() # Pagination page = self.paginate_queryset(products) if page is not None: serializer = ProductListSerializer(page, many=True, context={'request': request}) return self.get_paginated_response(serializer.data) serializer = ProductListSerializer(products, many=True, context={'request': request}) return Response(serializer.data) class ReviewViewSet(viewsets.ModelViewSet): """ViewSet für Review-API""" queryset = Review.objects.select_related('user', 'product').all() serializer_class = ReviewSerializer permission_classes = [IsAuthenticatedOrReadOnly] filter_backends = [DjangoFilterBackend] filterset_fields = ['product', 'rating'] def perform_create(self, serializer): serializer.save(user=self.request.user) def get_queryset(self): queryset = super().get_queryset() product_id = self.request.query_params.get('product_id') if product_id: queryset = queryset.filter(product_id=product_id) return queryset @action(detail=False, methods=['get']) def my_reviews(self, request): """Reviews des aktuellen Users""" if not request.user.is_authenticated: return Response( {'error': 'Authentication required'}, status=status.HTTP_401_UNAUTHORIZED ) reviews = self.get_queryset().filter(user=request.user) serializer = self.get_serializer(reviews, many=True) return Response(serializer.data) class WishlistViewSet(viewsets.ModelViewSet): """ViewSet für Wishlist-API""" serializer_class = WishlistSerializer permission_classes = [IsAuthenticated] def get_queryset(self): return Wishlist.objects.filter(user=self.request.user) def perform_create(self, serializer): serializer.save(user=self.request.user) @action(detail=False, methods=['post']) def add_product(self, request): """Produkt zur Wunschliste hinzufügen""" product_id = request.data.get('product_id') if not product_id: return Response( {'error': 'product_id is required'}, status=status.HTTP_400_BAD_REQUEST ) try: product = Product.objects.get(id=product_id) wishlist, created = Wishlist.objects.get_or_create(user=request.user) wishlist.products.add(product) return Response({ 'message': 'Product added to wishlist', 'product_id': product_id }) except Product.DoesNotExist: return Response( {'error': 'Product not found'}, status=status.HTTP_404_NOT_FOUND ) @action(detail=False, methods=['post']) def remove_product(self, request): """Produkt von Wunschliste entfernen""" product_id = request.data.get('product_id') if not product_id: return Response( {'error': 'product_id is required'}, status=status.HTTP_400_BAD_REQUEST ) try: wishlist = Wishlist.objects.get(user=request.user) product = Product.objects.get(id=product_id) wishlist.products.remove(product) return Response({ 'message': 'Product removed from wishlist', 'product_id': product_id }) except (Wishlist.DoesNotExist, Product.DoesNotExist): return Response( {'error': 'Wishlist or product not found'}, status=status.HTTP_404_NOT_FOUND ) class CustomOrderViewSet(viewsets.ModelViewSet): """ViewSet für Custom Order-API""" serializer_class = CustomOrderSerializer permission_classes = [IsAuthenticated] filter_backends = [DjangoFilterBackend] filterset_fields = ['status', 'fursuit_type', 'style'] def get_queryset(self): return CustomOrder.objects.filter(user=self.request.user) def perform_create(self, serializer): serializer.save(user=self.request.user) @action(detail=True, methods=['post']) def update_status(self, request, pk=None): """Status eines Custom Orders aktualisieren""" custom_order = self.get_object() new_status = request.data.get('status') if new_status not in dict(CustomOrder.STATUS_CHOICES): return Response( {'error': 'Invalid status'}, status=status.HTTP_400_BAD_REQUEST ) custom_order.status = new_status custom_order.save() serializer = self.get_serializer(custom_order) return Response(serializer.data) class GalleryImageViewSet(viewsets.ReadOnlyModelViewSet): """ViewSet für Galerie-API""" queryset = GalleryImage.objects.select_related('product').all() serializer_class = GalleryImageDetailSerializer permission_classes = [IsAuthenticatedOrReadOnly] filter_backends = [DjangoFilterBackend] filterset_fields = ['is_featured', 'fursuit_type', 'style'] @action(detail=False, methods=['get']) def featured(self, request): """Featured Galerie-Bilder""" images = self.get_queryset().filter(is_featured=True) serializer = self.get_serializer(images, many=True) return Response(serializer.data) @action(detail=False, methods=['get']) def by_product(self, request): """Bilder nach Produkt filtern""" product_id = request.query_params.get('product_id') if not product_id: return Response( {'error': 'product_id is required'}, status=status.HTTP_400_BAD_REQUEST ) images = self.get_queryset().filter(product_id=product_id) serializer = self.get_serializer(images, many=True) return Response(serializer.data) class CartViewSet(viewsets.ViewSet): """ViewSet für Warenkorb-API""" permission_classes = [IsAuthenticated] @action(detail=False, methods=['get']) def get_cart(self, request): """Warenkorb abrufen""" # Hier würde die Warenkorb-Logik implementiert # Für jetzt ein Beispiel-Response cart_data = { 'items': [], 'subtotal': 0, 'shipping_cost': 5.99, 'total': 5.99, 'item_count': 0 } serializer = CartSerializer(cart_data) return Response(serializer.data) @action(detail=False, methods=['post']) def add_item(self, request): """Item zum Warenkorb hinzufügen""" product_id = request.data.get('product_id') quantity = request.data.get('quantity', 1) if not product_id: return Response( {'error': 'product_id is required'}, status=status.HTTP_400_BAD_REQUEST ) try: product = Product.objects.get(id=product_id) # Hier würde die Warenkorb-Logik implementiert return Response({ 'message': 'Product added to cart', 'product_id': product_id, 'quantity': quantity }) except Product.DoesNotExist: return Response( {'error': 'Product not found'}, status=status.HTTP_404_NOT_FOUND ) @action(detail=False, methods=['post']) def update_quantity(self, request): """Menge eines Items aktualisieren""" item_id = request.data.get('item_id') quantity = request.data.get('quantity') if not item_id or not quantity: return Response( {'error': 'item_id and quantity are required'}, status=status.HTTP_400_BAD_REQUEST ) # Hier würde die Warenkorb-Logik implementiert return Response({ 'message': 'Quantity updated', 'item_id': item_id, 'quantity': quantity }) @action(detail=False, methods=['post']) def remove_item(self, request): """Item aus Warenkorb entfernen""" item_id = request.data.get('item_id') if not item_id: return Response( {'error': 'item_id is required'}, status=status.HTTP_400_BAD_REQUEST ) # Hier würde die Warenkorb-Logik implementiert return Response({ 'message': 'Item removed from cart', 'item_id': item_id }) @action(detail=False, methods=['post']) def clear_cart(self, request): """Warenkorb leeren""" # Hier würde die Warenkorb-Logik implementiert return Response({ 'message': 'Cart cleared' }) class SearchViewSet(viewsets.ViewSet): """ViewSet für Such-API""" permission_classes = [IsAuthenticatedOrReadOnly] @action(detail=False, methods=['get']) def products(self, request): """Produkte suchen""" serializer = SearchFilterSerializer(data=request.query_params) if not serializer.is_valid(): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST ) data = serializer.validated_data queryset = Product.objects.select_related('category').all() # Suchfilter anwenden if data.get('query'): queryset = queryset.filter( Q(name__icontains=data['query']) | Q(description__icontains=data['query']) ) if data.get('category'): queryset = queryset.filter(category__slug=data['category']) if data.get('fursuit_type'): queryset = queryset.filter(fursuit_type=data['fursuit_type']) if data.get('style'): queryset = queryset.filter(style=data['style']) if data.get('min_price'): queryset = queryset.filter(base_price__gte=data['min_price']) if data.get('max_price'): queryset = queryset.filter(base_price__lte=data['max_price']) if data.get('on_sale'): queryset = queryset.filter(on_sale=data['on_sale']) if data.get('is_featured'): queryset = queryset.filter(is_featured=data['is_featured']) # Sortierung sort_by = data.get('sort_by', 'newest') if sort_by == 'newest': queryset = queryset.order_by('-created_at') elif sort_by == 'oldest': queryset = queryset.order_by('created_at') elif sort_by == 'price_low': queryset = queryset.order_by('base_price') elif sort_by == 'price_high': queryset = queryset.order_by('-base_price') elif sort_by == 'name': queryset = queryset.order_by('name') elif sort_by == 'rating': queryset = queryset.order_by('-average_rating') # Pagination page_size = data.get('page_size', 12) page = data.get('page', 1) start = (page - 1) * page_size end = start + page_size products = queryset[start:end] serializer = ProductListSerializer(products, many=True, context={'request': request}) return Response({ 'results': serializer.data, 'total': queryset.count(), 'page': page, 'page_size': page_size, 'pages': (queryset.count() + page_size - 1) // page_size })