From 658cd59511e39edb8408058a92ef5dfc757d55f5 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Tue, 30 Dec 2025 11:37:42 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20ConfigurableProduct=20=D0=B2=20=D0=B0?= =?UTF-8?q?=D0=B4=D0=BC=D0=B8=D0=BD=D0=BA=D0=B5=20Django?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлены imports для ConfigurableProduct, ConfigurableProductOption, ConfigurableProductAttribute. Создан ConfigurableProductAdmin с инлайнами для вариантов и атрибутов. Поля variant_sku отображается в readonly режиме. Добавлен счетчик вариантов в list_display с цветовой индикацией. Организованы fieldsets для удобного редактирования. --- myproject/products/admin.py | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/myproject/products/admin.py b/myproject/products/admin.py index db9a96d..c9d67a0 100644 --- a/myproject/products/admin.py +++ b/myproject/products/admin.py @@ -6,6 +6,7 @@ import nested_admin from .models import ProductCategory, ProductTag, Product, ProductKit, KitItem from .models import ProductPhoto, ProductKitPhoto, ProductCategoryPhoto from .models import ProductVariantGroup, KitItemPriority, SKUCounter, CostPriceHistory +from .models import ConfigurableProduct, ConfigurableProductOption, ConfigurableProductAttribute from .admin_displays import ( format_quality_badge, format_quality_display, @@ -940,3 +941,57 @@ admin.site.register(ProductCategory, ProductCategoryAdminWithPhotos) admin.site.register(ProductTag, ProductTagAdmin) admin.site.register(Product, ProductAdminWithPhotos) admin.site.register(ProductKit, ProductKitAdminWithItemsAndPhotos) + + +# === Админка для ConfigurableProduct === + +class ConfigurableProductOptionInline(admin.TabularInline): + """Инлайн для вариантов вариативного товара""" + model = ConfigurableProductOption + extra = 0 + fields = ('kit', 'product', 'variant_sku', 'is_default', 'attributes') + readonly_fields = ('variant_sku',) + verbose_name = "Вариант" + verbose_name_plural = "Варианты" + + +class ConfigurableProductAttributeInline(admin.TabularInline): + """Инлайн для атрибутов родительского товара""" + model = ConfigurableProductAttribute + extra = 0 + fields = ('name', 'option', 'kit', 'product', 'position', 'visible') + verbose_name = "Атрибут" + verbose_name_plural = "Атрибуты" + + +@admin.register(ConfigurableProduct) +class ConfigurableProductAdmin(admin.ModelAdmin): + """Админка для вариативных товаров""" + list_display = ('name', 'sku', 'status', 'get_options_count', 'created_at') + list_filter = ('status', 'created_at') + search_fields = ('name', 'sku', 'description') + readonly_fields = ('created_at', 'updated_at', 'slug') + inlines = [ConfigurableProductOptionInline, ConfigurableProductAttributeInline] + + fieldsets = ( + ('Основная информация', { + 'fields': ('name', 'sku', 'slug', 'status') + }), + ('Описание', { + 'fields': ('short_description', 'description') + }), + ('Служебная информация', { + 'fields': ('created_at', 'updated_at'), + 'classes': ('collapse',) + }), + ) + + def get_options_count(self, obj): + """Количество вариантов""" + count = obj.options.count() + return format_html( + '{}', + '#28a745' if count > 0 else '#6c757d', + count + ) + get_options_count.short_description = 'Вариантов'