From d0dfa3eaa7b14a5c74ef96dd1e9b22dd38ad2fc7 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sat, 2 Aug 2025 18:57:46 +0330 Subject: [PATCH] Add ShopModel and integrate with ProductModel - Created ShopModel with fields for shop name, description, and user association. - Updated ProductModel to include a foreign key relationship with ShopModel. - Added admin interface for ShopModel with search functionality. - Created migrations for ShopModel and its integration with ProductModel. --- backend/account/migrations/0029_shopmodel.py | 28 ++++++++++++++++ backend/account/models.py | 14 ++++++++ backend/core/settings/unfold_conf.py | 5 +++ backend/product/admin.py | 16 +++++++-- ...nt_variant_slider_category_idx_and_more.py | 33 +++++++++++++++++++ .../migrations/0052_productmodel_shop.py | 20 +++++++++++ backend/product/models.py | 3 +- 7 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 backend/account/migrations/0029_shopmodel.py create mode 100644 backend/product/migrations/0051_remove_productvariant_variant_slider_category_idx_and_more.py create mode 100644 backend/product/migrations/0052_productmodel_shop.py diff --git a/backend/account/migrations/0029_shopmodel.py b/backend/account/migrations/0029_shopmodel.py new file mode 100644 index 0000000..d213a57 --- /dev/null +++ b/backend/account/migrations/0029_shopmodel.py @@ -0,0 +1,28 @@ +# Generated by Django 5.1.2 on 2025-08-02 15:21 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0028_newsmodel_is_read'), + ] + + operations = [ + migrations.CreateModel( + name='ShopModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('shop_name', models.CharField(max_length=100, verbose_name='نام فروشگاه')), + ('shop_description', models.TextField(verbose_name='توضیحات فروشگاه')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='shop', to=settings.AUTH_USER_MODEL, verbose_name='کاربر')), + ], + options={ + 'verbose_name': 'فروشگاه', + 'verbose_name_plural': 'فروشگاه ها', + }, + ), + ] diff --git a/backend/account/models.py b/backend/account/models.py index ad85788..58a3998 100644 --- a/backend/account/models.py +++ b/backend/account/models.py @@ -120,6 +120,20 @@ class User(AbstractBaseUser, PermissionsMixin): return self.phone + +class ShopModel(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='shop', verbose_name='کاربر') + shop_name = models.CharField(max_length=100, verbose_name='نام فروشگاه') + shop_description = models.TextField(verbose_name='توضیحات فروشگاه') + + def __str__(self): + return f"{self.user.phone} - {self.shop_name}" + + class Meta: + verbose_name = 'فروشگاه' + verbose_name_plural = 'فروشگاه ها' + + class UserAddressModel(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='address', verbose_name='کاربر') name = models.CharField(max_length=30, verbose_name='نام ادرس') diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py index 8c50b69..47b4a4f 100644 --- a/backend/core/settings/unfold_conf.py +++ b/backend/core/settings/unfold_conf.py @@ -107,6 +107,11 @@ UNFOLD = { "link": reverse_lazy("admin:order_ordermodel_changelist"), "badge": "utils.admin.admin_pending_count", }, + { + "title": _("فروشگاه ها"), + "icon": "storefront", + "link": reverse_lazy("admin:account_shopmodel_changelist"), + }, ], }, diff --git a/backend/product/admin.py b/backend/product/admin.py index 783659a..92c0997 100644 --- a/backend/product/admin.py +++ b/backend/product/admin.py @@ -41,6 +41,18 @@ class InPackItemsAdmin(ModelAdmin, ImportExportModelAdmin): "widget": ArrayWidget, } } +from account.models import ShopModel +@admin.register(ShopModel) +class ShopModelAdmin(ModelAdmin, ImportExportModelAdmin): + search_fields = ['name'] + compressed_fields = True + warn_unsaved_form = True + + formfield_overrides = { + ArrayField: { + "widget": ArrayWidget, + } + } class AttributeValueInLine(StackedInline): @@ -180,13 +192,13 @@ class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin): readonly_fields = ('slug', 'created_at') search_fields = ['name', 'description', ] list_filter = ['show', 'category'] - autocomplete_fields = ['related_products', ] + autocomplete_fields = ['related_products', 'shop'] # compressed_fields = True warn_unsaved_form = True actions_list = ['redirect_to_learn', 'update_products_price'] list_display = ['display_image', 'display_price', 'view', 'show', 'rating', 'category', 'created_at'] fieldsets = ( - ('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'related_products', 'show',), "classes": ["tab"],}), + ('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'related_products', 'show', 'shop'), "classes": ["tab"],}), ('فیلد های سيو', {'fields': ('meta_description', 'meta_keywords', 'meta_rating', 'slug'), "classes": ["tab"],}), ('فیلد های مربوط به کاربر', {'fields': ('rating', 'view',), "classes": ["tab"],}), # ('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],}) diff --git a/backend/product/migrations/0051_remove_productvariant_variant_slider_category_idx_and_more.py b/backend/product/migrations/0051_remove_productvariant_variant_slider_category_idx_and_more.py new file mode 100644 index 0000000..54a04c1 --- /dev/null +++ b/backend/product/migrations/0051_remove_productvariant_variant_slider_category_idx_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.1.2 on 2025-08-02 15:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0050_commentmodel_comment_product_idx_and_more'), + ] + + operations = [ + migrations.RemoveIndex( + model_name='productvariant', + name='variant_slider_category_idx', + ), + migrations.RemoveIndex( + model_name='productvariant', + name='variant_slider_stock_idx', + ), + migrations.RemoveIndex( + model_name='productvariant', + name='variant_slider_discount_idx', + ), + migrations.RemoveIndex( + model_name='productvariant', + name='variant_slider_created_idx', + ), + migrations.RemoveIndex( + model_name='productvariant', + name='variant_currency_idx', + ), + ] diff --git a/backend/product/migrations/0052_productmodel_shop.py b/backend/product/migrations/0052_productmodel_shop.py new file mode 100644 index 0000000..b69b503 --- /dev/null +++ b/backend/product/migrations/0052_productmodel_shop.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.2 on 2025-08-02 15:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0029_shopmodel'), + ('product', '0051_remove_productvariant_variant_slider_category_idx_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='productmodel', + name='shop', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='products', to='account.shopmodel', verbose_name='فروشگاه'), + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index 02dfa2a..a221f92 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -122,7 +122,7 @@ 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='محصولات مرتبط') - + shop = models.ForeignKey('account.ShopModel', on_delete=models.CASCADE, related_name='products', verbose_name='فروشگاه', blank=True, null=True) @@ -287,7 +287,6 @@ class ProductVariant(models.Model): verbose_name = 'تنوع محصول' verbose_name_plural = 'تنوع‌های محصول' indexes = [ - # Existing indexes models.Index(fields=['product', 'price', 'created_at'], name='idx_product_price_created'), models.Index(fields=['in_stock', 'discount'], name='idx_stock_discount'), models.Index(fields=['created_at'], name='idx_created'),