from rest_framework import serializers from django.db.models import Avg from core.apps.accounts.choices import AccountType from core.apps.api.models import AdModel, AdVariant, Category, AdImage, AdOption from core.apps.accounts.models import UserLike from core.apps.api.choices import AdVariantType class AdOptionSerializer(serializers.ModelSerializer): class Meta: model = AdOption fields = [ "id", "name", "value", ] class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ["id", "name"] class AdImageSerializer(serializers.ModelSerializer): class Meta: model = AdImage fields = [ "image", "ad_variant" ] def to_representation(self, instance): data = super().to_representation(instance) if instance.ad_variant is None: data.pop("ad_variant", None) return data class AdVariantSerializer(serializers.ModelSerializer): class Meta: model = AdVariant fields = [ "id", "variant", "value", "is_available", "price", "discount", ] class BaseAdSerializer(serializers.ModelSerializer): is_liked = serializers.SerializerMethodField() star = serializers.SerializerMethodField() comment_count = serializers.SerializerMethodField() class Meta: model = AdModel fields = [ "id", "name", "price", "image", "is_liked", "star", "comment_count", ] def get_star(self, obj): avg = obj.feedback.aggregate(avg=Avg("star"))["avg"] return avg or 0 def get_comment_count(self, obj): count = obj.feedback.count() return count or 0 def get_is_liked(self, obj): request = self.context.get("request") user = getattr(request, "user", None) if not user or not user.is_authenticated: return False return UserLike.objects.filter(user=user, ad=obj).exists() class ListAdSerializer(BaseAdSerializer): price = serializers.SerializerMethodField() discount = serializers.SerializerMethodField() class Meta(BaseAdSerializer.Meta): fields = [ "id", "name", "price", "image", "star", "comment_count", "discount", "is_liked", ] def _get_first_variant(self, obj): if not hasattr(self, "_variant_cache"): self._variant_cache = {} if obj.id not in self._variant_cache: self._variant_cache[obj.id] = obj.variants.order_by("price").first() return self._variant_cache[obj.id] def get_price(self, obj): variant = self._get_first_variant(obj) if not variant: return obj.price return variant.price if variant else 0 def get_discount(self, obj): variant = self._get_first_variant(obj) return variant.discount if variant else -1.0 class FullListAdSerializer(serializers.Serializer): ads = ListAdSerializer(many=True) categories = serializers.SerializerMethodField() colors = serializers.SerializerMethodField() sizes = serializers.SerializerMethodField() min_price = serializers.SerializerMethodField() max_price = serializers.SerializerMethodField() def get_categories(self, obj): ads = obj.get("ads", []) category_ids = set() categories = [] for ad in ads: category = ad.category if category and category.id not in category_ids: category_ids.add(category.id) categories.append(category) return CategorySerializer(categories, many=True).data def get_colors(self, obj): ads = obj.get("ads", []) color_values = set() for ad in ads: variants = getattr(ad, "variants", []) for v in variants.all(): if v.variant == AdVariantType.COLOR: color_values.add(v.value) return list(color_values) def get_sizes(self, obj): ads = obj.get("ads", []) size_values = set() for ad in ads: variants = getattr(ad, "variants", []) for v in variants.all(): if v.variant == AdVariantType.SIZE: size_values.add(v.value) return list(size_values) def get_min_price(self, obj): ads = obj.get("ads", []) prices = [] for ad in ads: ad_data = ListAdSerializer(ad, context=self.context).data price = ad_data.get("price") if price is not None: prices.append(price) return min(prices) if prices else None def get_max_price(self, obj): ads = obj.get("ads", []) prices = [] for ad in ads: ad_data = ListAdSerializer(ad, context=self.context).data price = ad_data.get("price") if price is not None: prices.append(price) return max(prices) if prices else None class RetrieveAdSerializer(BaseAdSerializer): variants = AdVariantSerializer(many=True, read_only=True) images = serializers.SerializerMethodField() colors = serializers.SerializerMethodField() sizes = serializers.SerializerMethodField() creator = serializers.SerializerMethodField() options = AdOptionSerializer(many=True, read_only=True) class Meta(BaseAdSerializer.Meta): fields = [ "id", "name", "price", "image", "star", "comment_count", "is_liked", "images", "variants", "colors", "sizes", "creator", "description", "options" ] def get_images(self, obj): objects = obj.images.all() return AdImageSerializer(objects, many=True, context=self.context).data def get_colors(self, obj): color_values = set() variants = getattr(obj, "variants", []) for v in variants.all(): if v.variant == AdVariantType.COLOR: color_values.add(v.value) return list(color_values) def get_sizes(self, obj): size_values = set() variants = getattr(obj, "variants", []) for v in variants.all(): if v.variant == AdVariantType.SIZE: size_values.add(v.value) return list(size_values) def get_creator(self, obj): user = obj.user user_type = user.account_type request = self.context.get("request") avatar_url = request.build_absolute_uri(user.avatar.url) if user.avatar else None if user_type == AccountType.BUSINESS: return { "username": user.business.name, "avatar": avatar_url, "create_at": user.validated_at, "last_live": "endi qo'shamiz! waiting pls ))" } else: username = f"{user.first_name} {user.last_name}" return { "username": username, "avatar": avatar_url, "create_at": user.validated_at, "last_live": "endi qo'shamiz! waiting pls ))" } class CreateAdSerializer(BaseAdSerializer): class Meta(BaseAdSerializer.Meta): ...