From d8a588ca86249be26092c6c02aa3380c1d92cc75 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 11 Feb 2025 23:02:08 +0330 Subject: [PATCH] change color image video field and place it in product varient model --- backend/product/admin.py | 73 +++++++++++-------- ...ove_productmodel_in_pack_items_and_more.py | 22 ++++++ ...el_remove_attributevalue_color_and_more.py | 48 ++++++++++++ backend/product/models.py | 23 +++++- backend/product/serializers.py | 27 ++++++- 5 files changed, 157 insertions(+), 36 deletions(-) create mode 100644 backend/product/migrations/0021_remove_productmodel_in_pack_items_and_more.py create mode 100644 backend/product/migrations/0022_productimagemodel_remove_attributevalue_color_and_more.py diff --git a/backend/product/admin.py b/backend/product/admin.py index 96aaceb..334e46f 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -77,11 +77,24 @@ class AttributeValueAdmin(ModelAdmin, ImportExportModelAdmin): "widget": ArrayWidget, } } - def get_form(self, request, obj=None, change=False, **kwargs): - form = super().get_form(request, obj, change, **kwargs) - form.base_fields["color"].widget = UnfoldAdminColorInputWidget() - return form + # def get_form(self, request, obj=None, change=False, **kwargs): + # form = super().get_form(request, obj, change, **kwargs) + # form.base_fields["color"].widget = UnfoldAdminColorInputWidget() + # return form +@admin.register(ProductImageModel) +class ProductImagesAdmin(ModelAdmin): + import_form_class = ImportForm + export_form_class = ExportForm + search_fields = ['name'] + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } @@ -92,14 +105,14 @@ class ProductVariantInLine(StackedInline): show_change_link = True tab = True min_num = 1 - autocomplete_fields = ['attributes'] + autocomplete_fields = ['attributes', 'in_pack_items', 'images'] # search_fields = [''] - def get_form(self, request, obj=None, change=False, **kwargs): - form = super().get_form(request, obj, change, **kwargs) - form.base_fields["color"].widget = UnfoldAdminColorInputWidget() - return form + def formfield_for_dbfield(self, db_field, request, **kwargs): + if db_field.name == 'color': + kwargs['widget'] = UnfoldAdminColorInputWidget() + return super().formfield_for_dbfield(db_field, request, **kwargs) @@ -138,15 +151,15 @@ class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin): readonly_fields = ('slug', ) search_fields = ['name', 'description', ] list_filter = ['show', 'category'] - autocomplete_fields = ['related_products', 'in_pack_items',] + autocomplete_fields = ['related_products', ] # compressed_fields = True warn_unsaved_form = True - list_display = ['display_image', 'display_price', 'view', 'show', 'rating', 'category', ] + list_display = ['display_price', 'view', 'show', 'rating', 'category', ] fieldsets = ( ('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'related_products', 'show',), "classes": ["tab"],}), ('فیلد های سيو', {'fields': ('meta_description', 'meta_keywords', 'meta_rating', 'slug'), "classes": ["tab"],}), ('فیلد های مربوط به کاربر', {'fields': ('rating', 'view',), "classes": ["tab"],}), - ('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],}) + # ('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],}) ) formfield_overrides = { @@ -163,24 +176,24 @@ class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin): return obj.get_toman_price() display_price.short_description = 'قیمت تومانی' - @display(description='محصول', header=True) - def display_image(self, instance): - if instance and instance.variants.first() and instance.variants.first().attributes.first(): - image = instance.variants.first().attributes.first().image.url if instance.variants.first().attributes.first().image else None - else: - image = None - return [ - instance.name, - None, - None, - { - "path": image, - "height": 30, - "width": 30, - "borderless": True, - # "squared": True, - }, - ] + # @display(description='محصول', header=True) + # def display_image(self, instance): + # if instance and instance.variants.first() and instance.variants.first().attributes.first(): + # image = instance.variants.first().attributes.first().image.url if instance.variants.first().attributes.first().image else None + # else: + # image = None + # return [ + # instance.name, + # None, + # None, + # { + # "path": image, + # "height": 30, + # "width": 30, + # "borderless": True, + # # "squared": True, + # }, + # ] # @display( # description=("نمایش در صفحه ی اصلی"), # label={ diff --git a/backend/product/migrations/0021_remove_productmodel_in_pack_items_and_more.py b/backend/product/migrations/0021_remove_productmodel_in_pack_items_and_more.py new file mode 100644 index 0000000..1e9785c --- /dev/null +++ b/backend/product/migrations/0021_remove_productmodel_in_pack_items_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.2 on 2025-02-11 17:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0020_productvariant_max_price_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='productmodel', + name='in_pack_items', + ), + migrations.AddField( + model_name='productvariant', + name='in_pack_items', + field=models.ManyToManyField(blank=True, to='product.inpackitems', verbose_name='ایتم های داخل پک'), + ), + ] diff --git a/backend/product/migrations/0022_productimagemodel_remove_attributevalue_color_and_more.py b/backend/product/migrations/0022_productimagemodel_remove_attributevalue_color_and_more.py new file mode 100644 index 0000000..280d9c6 --- /dev/null +++ b/backend/product/migrations/0022_productimagemodel_remove_attributevalue_color_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 5.1.2 on 2025-02-11 19:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0021_remove_productmodel_in_pack_items_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='ProductImageModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30, verbose_name='نام عکس')), + ('image', models.ImageField(upload_to='product_images/')), + ], + ), + migrations.RemoveField( + model_name='attributevalue', + name='color', + ), + migrations.RemoveField( + model_name='attributevalue', + name='image', + ), + migrations.RemoveField( + model_name='attributevalue', + name='video', + ), + migrations.AddField( + model_name='productvariant', + name='color', + field=models.CharField(blank=True, max_length=7, null=True, verbose_name='رنک'), + ), + migrations.AddField( + model_name='productvariant', + name='video', + field=models.FileField(blank=True, null=True, upload_to='product_videos/', verbose_name='ویدیو'), + ), + migrations.AddField( + model_name='productvariant', + name='images', + field=models.ManyToManyField(to='product.productimagemodel', verbose_name='عکس ها'), + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index b148823..e06e872 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -111,7 +111,6 @@ class ProductModel(models.Model): created_at = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت محصول') category = models.ForeignKey(SubCategoryModel, null=True, on_delete=models.SET_NULL, related_name='products', verbose_name='دسته بندی محصول') related_products = models.ManyToManyField('self', blank=True, verbose_name='محصولات مرتبط') - in_pack_items = models.ManyToManyField(InPackItems, blank=True, verbose_name='ایتم های داخل پک') @@ -198,15 +197,27 @@ class AttributeType(models.Model): class AttributeValue(models.Model): attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE, blank=True, null=True) value = models.CharField(verbose_name='مقدار نوع اتربیوت', max_length=100, blank=True, null=True) - color = models.CharField(verbose_name='رنک', max_length=7, blank=True, null=True) - image = models.ImageField(upload_to='product_images/') - video = models.FileField(upload_to='product_videos/', blank=True, null=True, verbose_name='ویدیو') class Meta: unique_together = ('attribute_type', 'value') def __str__(self): return f"{self.attribute_type.name}: {self.value}" + +class ProductImageModel(models.Model): + name = models.CharField(max_length=30, verbose_name='نام عکس') + image = models.ImageField(upload_to='product_images/') + + def __str__(self): + return self.name + + class Meta: + verbose_name = 'عکس محصولات' + verbose_name_plural = 'عکس های محصولات' + + + + class ProductVariant(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول') attributes = models.ManyToManyField(AttributeValue, verbose_name='ویژگی‌ها', related_name='variant') @@ -219,9 +230,13 @@ class ProductVariant(models.Model): ('toman', 'تومان'), ('derham', 'درهم') ) + in_pack_items = models.ManyToManyField(InPackItems, blank=True, verbose_name='ایتم های داخل پک') sell = models.IntegerField(default=0, verbose_name='فروش') currency = models.CharField(verbose_name='نوع ارز', max_length=20, choices=currency_type) discount = models.SmallIntegerField(default=0, verbose_name='تخفیف') + color = models.CharField(verbose_name='رنک', max_length=7, blank=True, null=True) + images = models.ManyToManyField(ProductImageModel, verbose_name='عکس ها') + video = models.FileField(upload_to='product_videos/', blank=True, null=True, verbose_name='ویدیو') class Meta: verbose_name = 'تنوع محصول' verbose_name_plural = 'تنوع‌های محصول' diff --git a/backend/product/serializers.py b/backend/product/serializers.py index 4907698..f3bc036 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -30,9 +30,24 @@ class AttributeValueSerialzier(serializers.ModelSerializer): 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): attributes = AttributeValueSerialzier(many=True) price = serializers.SerializerMethodField() + in_pack_items = InPackItemsSerialzier(many=True) + images = ProductImageSerailizer(many=True) class Meta: model = ProductVariant exclude = ('min_price', 'max_price','sell', 'currency', 'product') @@ -42,6 +57,11 @@ class ProductVariantSerialzier(serializers.ModelSerializer): toman_price = obj.get_toman_price(dollor_price=dollor_price) return "{:,.0f} تومان".format(toman_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) @@ -49,11 +69,12 @@ class ProductVariantSerialzier(serializers.ModelSerializer): class DynamicProductSerializer(serializers.ModelSerializer): - variants = ProductVariantSerialzier(many=True) + variants = serializers.SerializerMethodField() # variants_colors = serializers.SerializerMethodField() is_new = serializers.SerializerMethodField() related_products = serializers.SerializerMethodField() details = ProductDetailSerializer(many=True, read_only=True) + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) view_type = self.context.get('view_type', 'all') @@ -74,7 +95,9 @@ class DynamicProductSerializer(serializers.ModelSerializer): 'instance': ['name', 'description', 'rating', 'slug', 'meta_description', 'meta_keywords', 'meta_rating', 'category', 'related_products', 'details', 'in_pack_items', 'variants'], 'chat': ['name', 'description', 'variants'] } - + + def get_variants(self, obj): + return ProductVariantSerialzier(instance=obj.variants.all(), many=True, context=self.context).data # def get_variants_colors(self, obj): # varients = obj.variants.all()