from .models import * from rest_framework import serializers from django.utils import timezone from datetime import timedelta from django.contrib.auth.models import AnonymousUser class DetailSerializer(serializers.ModelSerializer): texts = serializers.SerializerMethodField() class Meta: model = DetailModel exclude = ['detail_model', 'detail_text1', 'detail_text2', 'detail_text3', 'detail_text4'] def get_texts(self, obj): return [ text for text in [ obj.detail_text1, obj.detail_text2, obj.detail_text3, obj.detail_text4, ] if text ] class ProductDetailSerializer(serializers.ModelSerializer): details = DetailSerializer(many=True, read_only=True) detail_category = serializers.StringRelatedField() class Meta: model = ProductDetailModel exclude = ['name'] class AttributeTypeSerialzier(serializers.ModelSerializer): class Meta: model = AttributeType fields = "__all__" class AttributeValueSerialzier(serializers.ModelSerializer): attribute_type = AttributeTypeSerialzier() class Meta: model = AttributeValue fields = "__all__" class InPackItemsSerialzier(serializers.ModelSerializer): class Meta: model = InPackItems fields = '__all__' class ProductImageSerailizer(serializers.ModelSerializer): class Meta: model = ProductImageModel fields = '__all__' class ProductVariantSerialzier(serializers.ModelSerializer): product_attributes = AttributeValueSerialzier(many=True) in_pack_items = InPackItemsSerialzier(many=True) images = ProductImageSerailizer(many=True) details = ProductDetailSerializer(many=True, read_only=True) cart_quantity = serializers.SerializerMethodField() price = serializers.SerializerMethodField() class Meta: model = ProductVariant exclude = ('min_price', 'sell', 'currency', 'product', 'input_price', 'price_in_dollor') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) view_type = self.context.get('view_type', None) if view_type == 'list': self.fields.pop('in_pack_items', None) def get_cart_quantity(self, obj): request = self.context.get('request') if not request or not request.user.is_authenticated: return 0 cart_items = self.context.get('cart_items', []) if cart_items: for item in cart_items: if item['product']['id'] == obj.id: return item['quantity'] return 0 def get_price(self, obj): return f'{obj.price:,.0f} تومان' class SubCategorySerializer(serializers.ModelSerializer): product_count = serializers.SerializerMethodField() parent = serializers.SerializerMethodField() class Meta: model = SubCategoryModel fields = ['id', 'name', 'slug', 'icon', 'meta_title', 'meta_description', 'product_count', 'parent', 'image'] def get_product_count(self, obj): # Use annotated product_count if available (from optimized query) # Otherwise fall back to counting (for backward compatibility) return getattr(obj, 'product_count', obj.products.count()) def get_parent(self, obj): return obj.parent.name class UnitCategorySerializer(serializers.ModelSerializer): class Meta: model = UnitCategoryModel fields = ['id', 'name', 'slug', 'icon', 'meta_title', 'meta_description', 'image'] class MainCategorySerializer(serializers.ModelSerializer): subcategorys = SubCategorySerializer(many=True) class Meta: model = MainCategoryModel fields = ['id', 'name', 'slug', 'icon', 'meta_title', 'meta_description', 'subcategorys', 'image', 'video'] class DynamicProductSerializer(serializers.ModelSerializer): variants = serializers.SerializerMethodField() colors = serializers.SerializerMethodField() category = SubCategorySerializer(read_only=True) is_new = serializers.SerializerMethodField() related_products = serializers.SerializerMethodField() added_to_favorites = serializers.SerializerMethodField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) view_type = self.context.get('view_type', 'all') if view_type != 'all': allowed_fields = self.Meta.view_type[view_type] allowed = set(allowed_fields) existing = set(self.fields.keys()) for field_name in existing - allowed: self.fields.pop(field_name) class Meta: model = ProductModel fields = "__all__" view_type = { 'list': ['id', 'name', 'rating', 'slug', 'category', 'variants', 'colors', 'image'], 'slider': ['id', 'name', 'rating', 'slug', 'category', 'variants', 'colors', 'image'], 'instance': ['id', 'name', 'description', 'rating', 'slug', 'meta_description', 'meta_keywords', 'meta_rating', 'category', 'related_products', 'in_pack_items', 'variants', 'colors', 'added_to_favorites', 'image'], 'chat': ['id', 'name', 'description', 'variants', 'image'] } def get_added_to_favorites(self, obj): from account.models import UserFavorites request = self.context.get('request') if not request or not request.user.is_authenticated: return False # not logged in users haven't added anything # Use exists() with filter instead of fetching all products return UserFavorites.objects.filter(user=request.user, products=obj).exists() def get_variants(self, obj): view_type = self.context.get('view_type') if view_type == 'slider': varients = obj.variants.filter(slider_category__isnull=False) else: varients = obj.variants.all() colors = set(varient.color for varient in varients) return ProductVariantSerialzier(instance=varients, many=True, context=self.context).data def get_colors(self, obj): # Use values_list to get only color field, reducing data transfer colors = obj.variants.values_list('color', flat=True).distinct() return list(filter(None, colors)) # Filter out None values def get_is_new(self, obj): return timezone.now() < obj.created_at + timedelta(days=7) def get_related_products(self, obj): if obj.related_products.all().count() >= 5: # Limit to 10 related products related_products = obj.related_products.all()[:10] else: # Limit category products and exclude current product related_products = obj.category.products.exclude(id=obj.id)[:10] serializer = DynamicProductSerializer( related_products, many=True, context={ 'view_type': 'list', 'request': self.context.get('request') } ) return serializer.data class CommentSerializer(serializers.ModelSerializer): class Meta: model = CommentModel exclude = ('review_status', ) read_only_fields = ('review_status', 'product', 'user') class BotProductSerializer(serializers.ModelSerializer): class Meta: model = ProductModel fields = [ 'pk', 'name' ]