261 lines
9.4 KiB
Python
261 lines
9.4 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()
|
|
price_after_discount = serializers.SerializerMethodField()
|
|
special_discount_amount = serializers.SerializerMethodField()
|
|
special_discount_link = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = ProductVariant
|
|
exclude = ('min_price', 'sell', 'currency', 'product', 'input_price', 'price_in_dollor', 'profit', 'special_discount_percent')
|
|
|
|
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_special_discount_amount(self, obj):
|
|
if obj.special_discount_percent:
|
|
special_discount_amount = obj.profit * (obj.special_discount_percent / 100)
|
|
return f'{special_discount_amount:,.0f} تومانءءء'
|
|
else:
|
|
return None
|
|
|
|
def get_special_discount_link(self, obj):
|
|
return 'https://'
|
|
|
|
def get_price_after_discount(self, obj):
|
|
return f'{obj.price_after_discount:,.0f} تومانءءء'
|
|
|
|
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()
|
|
best_deal_price_before_discount = serializers.SerializerMethodField()
|
|
best_deal_price_after_discount = serializers.SerializerMethodField()
|
|
best_deal_discount = serializers.SerializerMethodField()
|
|
main_image = 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', 'colors', 'image', 'best_deal_price_before_discount', 'best_deal_price_after_discount', 'best_deal_discount', 'main_image'],
|
|
'slider': ['id', 'name', 'rating', 'slug', 'category', 'variants', 'colors', 'image', 'best_deal_price_before_discount', 'best_deal_price_after_discount', 'best_deal_discount', ],
|
|
'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_main_image(self, obj):
|
|
if obj.image:
|
|
return obj.image.url
|
|
return obj.variants.first().images.first().image.url if obj.variants.exists() and obj.variants.first().images.exists() else None
|
|
|
|
def get_best_deal_price_before_discount(self, obj):
|
|
best_deal = obj.get_best_deal_variant()
|
|
if best_deal:
|
|
return f'{best_deal.price:,.0f} تومانءءء'
|
|
return 0
|
|
|
|
def get_best_deal_price_after_discount(self, obj):
|
|
best_deal = obj.get_best_deal_variant()
|
|
if best_deal:
|
|
price_after_discount = best_deal.price_after_discount
|
|
return f'{price_after_discount:,.0f} تومانءءء'
|
|
return 0
|
|
|
|
def get_best_deal_discount(self, obj):
|
|
best_deal = obj.get_best_deal_variant()
|
|
if best_deal:
|
|
return best_deal.discount
|
|
return 0
|
|
|
|
|
|
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'
|
|
]
|