Files
hossein-por-shop/backend/product/serializers.py
T
2025-12-04 13:37:55 +03:30

217 lines
7.3 KiB
Python

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')
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'
]