This commit is contained in:
A'zamov Samandar
2025-12-06 21:50:28 +05:00
parent 3aa20fdaa1
commit f5766aa319
140 changed files with 2376 additions and 1582 deletions

View File

@@ -1,2 +1,2 @@
from .home_api import * # noqa
from .ad import * # noqa
from .home_api import *
from .ad import *

View File

@@ -1,270 +1,148 @@
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.api.models import AdModel, AdVariantModel, CategoryModel, AdImageModel, AdOptionModel
from core.apps.accounts.models import UserLike
from core.apps.api.choices import AdVariantType
from core.apps.api.serializers.common.color import ListColorSerializer
from core.apps.api.serializers.common.size import ListSizeSerializer
class AdOptionSerializer(serializers.ModelSerializer):
class Meta:
model = AdOption
fields = [
"id",
"name",
"value",
]
model = AdOptionModel
fields = ["id", "name", "value"]
read_only_fields = ["id"]
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
model = CategoryModel
fields = ["id", "name"]
read_only_fields = ["id"]
class AdImageSerializer(serializers.ModelSerializer):
class Meta:
model = AdImage
fields = [
"image",
"ad_variant"
]
model = AdImageModel
fields = ["id", "image", "ad_variant", "is_primary", "order"]
read_only_fields = ["id"]
def to_representation(self, instance):
data = super().to_representation(instance)
if instance.ad_variant is None:
if not instance.ad_variant:
data.pop("ad_variant", None)
return data
class AdVariantSerializer(serializers.ModelSerializer):
color = ListColorSerializer()
size = ListSizeSerializer()
class Meta:
model = AdVariant
fields = [
"id",
"variant",
"value",
"is_available",
"price",
"discount",
]
model = AdVariantModel
fields = ["id", "size", "color", "is_available", "price", "stock_quantity"]
read_only_fields = ["id", "color_name"]
class BaseAdSerializer(serializers.ModelSerializer):
class AdListSerializer(serializers.ModelSerializer):
is_liked = serializers.SerializerMethodField()
star = serializers.SerializerMethodField()
comment_count = serializers.SerializerMethodField()
rating = serializers.SerializerMethodField()
reviews_count = serializers.SerializerMethodField()
class Meta:
model = AdModel
fields = [
"id",
"name",
"price",
"image",
"is_liked",
"star",
"comment_count",
]
fields = ["id", "name", "price", "image", "discount", "is_liked", "rating", "reviews_count", "is_available"]
read_only_fields = fields
def get_star(self, obj):
avg = obj.feedback.aggregate(avg=Avg("star"))["avg"]
return avg or 0
def get_rating(self, obj):
"""Get average rating from feedbacks"""
avg = obj.feedbacks.aggregate(avg=Avg("star"))["avg"]
return round(avg, 1) if avg else 0
def get_comment_count(self, obj):
count = obj.feedback.count()
return count or 0
def get_reviews_count(self, obj):
"""Get total count of feedbacks"""
return obj.feedbacks.count()
def get_is_liked(self, obj):
"""Check if current user liked this ad"""
request = self.context.get("request")
user = getattr(request, "user", None)
if not user or not user.is_authenticated:
if not request or not request.user.is_authenticated:
return False
return UserLike.objects.filter(user=user, ad=obj).exists()
return UserLike.objects.filter(user=request.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):
class AdDetailSerializer(AdListSerializer):
variants = AdVariantSerializer(many=True, read_only=True)
images = serializers.SerializerMethodField()
images = AdImageSerializer(many=True, read_only=True)
colors = serializers.SerializerMethodField()
sizes = serializers.SerializerMethodField()
creator = serializers.SerializerMethodField()
options = AdOptionSerializer(many=True, read_only=True)
category = CategorySerializer(read_only=True)
class Meta(BaseAdSerializer.Meta):
fields = [
"id",
"name",
"price",
"image",
"star",
"comment_count",
"is_liked",
class Meta(AdListSerializer.Meta):
fields = AdListSerializer.Meta.fields + [
"description",
"images",
"variants",
"colors",
"sizes",
"creator",
"description",
"options"
"options",
"category",
"ad_type",
"physical_product",
]
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)
"""Get unique colors from variants"""
return list(obj.variants.values_list("color", flat=True).distinct())
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)
"""Get unique sizes from variants"""
return list(obj.variants.values_list("size", flat=True).distinct())
def get_creator(self, obj):
"""Get creator information"""
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
avatar_url = None
if user.avatar and request:
avatar_url = request.build_absolute_uri(user.avatar.url)
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 ))"
}
if user.account_type == AccountType.BUSINESS:
username = user.business.name if hasattr(user, "business") else user.username
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 ))"
}
username = f"{user.first_name} {user.last_name}".strip() or user.username
return {
"id": user.id,
"username": username,
"avatar": avatar_url,
"account_type": user.account_type,
"joined_at": user.date_joined,
}
class CreateAdSerializer(BaseAdSerializer):
class Meta(BaseAdSerializer.Meta): ...
class AdCreateSerializer(serializers.ModelSerializer):
class Meta:
model = AdModel
fields = [
"name",
"ad_type",
"category",
"ad_category_type",
"discount",
"is_available",
"physical_product",
"plan",
"tags",
"image",
"description",
]
def create(self, validated_data):
validated_data["user"] = self.context["request"].user
return super().create(validated_data)

View File

@@ -1,26 +1,22 @@
from rest_framework import serializers
from django.db.models import Avg
from core.apps.api.models import AdModel, AdVariant
from core.apps.api.models import AdModel, AdVariantModel
from core.apps.accounts.models import UserLike
class AdVariantSerializer(serializers.ModelSerializer):
color_name = serializers.CharField(source="color.name", read_only=True)
class Meta:
model = AdVariant
fields = [
"variant",
"value",
"is_available",
"price",
"discount",
]
model = AdVariantModel
fields = ["id", "value", "color_name", "is_available", "price"]
read_only_fields = fields
class BaseHomeAdSerializer(serializers.ModelSerializer):
star = serializers.SerializerMethodField()
comment_count = serializers.SerializerMethodField()
price = serializers.SerializerMethodField()
discount = serializers.SerializerMethodField()
class HomeAdListSerializer(serializers.ModelSerializer):
"""Optimized serializer for home page ad listing"""
rating = serializers.SerializerMethodField()
reviews_count = serializers.SerializerMethodField()
is_liked = serializers.SerializerMethodField()
class Meta:
@@ -30,54 +26,25 @@ class BaseHomeAdSerializer(serializers.ModelSerializer):
"name",
"price",
"image",
"star",
"comment_count",
"rating",
"reviews_count",
"discount",
"is_liked",
]
read_only_fields = fields
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_rating(self, obj):
"""Get average rating"""
avg = obj.feedbacks.aggregate(avg=Avg("star"))["avg"]
return round(avg, 1) if avg else 0
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
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_reviews_count(self, obj):
"""Get feedback count"""
return obj.feedbacks.count()
def get_is_liked(self, obj):
"""Check if user liked this ad"""
request = self.context.get("request")
user = getattr(request, "user", None)
if not user or not user.is_authenticated:
if not request or not request.user.is_authenticated:
return False
return UserLike.objects.filter(user=user, ad=obj).exists()
class ListHomeAdSerializer(BaseHomeAdSerializer):
class Meta(BaseHomeAdSerializer.Meta): ...
class RetrieveHomeAdSerializer(BaseHomeAdSerializer):
class Meta(BaseHomeAdSerializer.Meta): ...
class CreateHomeAdSerializer(BaseHomeAdSerializer):
class Meta(BaseHomeAdSerializer.Meta): ...
return UserLike.objects.filter(user=request.user, ad=obj).exists()