Files
octopus/myproject/test_configurable_json.py
Andrey Smakotin def795f0ad Implement card-based interface for ConfigurableKitProduct attributes
This commit introduces a new user-friendly interface for managing product attributes:

1. **Form Changes** (products/forms.py):
   - Removed 'option' field from ConfigurableKitOptionForm (values now inline)
   - Updated ConfigurableKitProductAttributeFormSetCreate to only include name, position, visible
   - Updated BaseConfigurableKitProductAttributeFormSet validation for new structure

2. **Template Updates** (products/templates/products/configurablekit_form.html):
   - Replaced row-based attribute interface with card-based design
   - Each card contains:
     - Parameter name field
     - Position field
     - Visibility toggle
     - Inline value inputs with add/remove buttons
   - "Add parameter" button creates new cards
   - "Add value" button adds inline value inputs

3. **JavaScript Enhancements**:
   - addValueField(): Creates new value input with delete button
   - initAddValueBtn(): Initializes add value button for each card
   - addParameterBtn: Dynamically generates new parameter cards
   - serializeAttributeValues(): Converts inline values to JSON for POST submission
   - Form submission intercept to serialize data before sending

4. **View Updates** (products/views/configurablekit_views.py):
   - Both Create and Update views now have _save_attributes_from_cards() method
   - Reads attributes-X-values JSON from POST data
   - Creates ConfigurableKitProductAttribute for each parameter+value combination
   - Handles parameter deletion and visibility toggling

**Key Features**:
✓ One-time parameter name entry with multiple inline values
✓ Add/remove values without reloading page
✓ Add/remove entire parameters with one click
✓ No database changes required
✓ Better UX: card layout more intuitive than rows
✓ Proper JSON serialization for value transmission

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 20:54:14 +03:00

178 lines
7.9 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
"""
Тестовый скрипт для проверки что JSONField работает корректно
в модели ConfigurableKitOption (с поддержкой тенанта).
"""
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
from products.models.kits import ConfigurableKitProduct, ConfigurableKitOption, ProductKit
from django_tenants.utils import tenant_context
from tenants.models import Client
# Переходим в нужную схему (тенант)
try:
client = Client.objects.get(schema_name='grach')
print(f"✅ Найден тенант: {client.name} (schema: {client.schema_name})\n")
except Client.DoesNotExist:
print("❌ Тенант 'grach' не найден")
print("📝 Доступные тенанты:")
for c in Client.objects.all():
print(f" - {c.name} ({c.schema_name})")
exit(1)
# Весь тест в контексте тенанта
with tenant_context(client):
print("=" * 70)
print("ТЕСТ: JSONField в ConfigurableKitOption")
print("=" * 70)
# Проверка 1: Создание вариативного товара
print("\n1⃣ Проверка создания ConfigurableKitProduct...")
try:
configurable = ConfigurableKitProduct.objects.filter(name__icontains="тест").first()
if configurable:
print(f" ✅ Найден существующий товар: {configurable.name}")
else:
configurable = ConfigurableKitProduct.objects.create(
name="Тестовый букет JSON",
sku="TEST-BUCKET-JSON",
description="Тестовый товар для проверки JSON атрибутов"
)
print(f" ✅ Создан новый товар: {configurable.name}")
except Exception as e:
print(f" ❌ Ошибка: {e}")
exit(1)
# Проверка 2: Создание вариантов с JSON атрибутами
print("\n2⃣ Проверка создания ConfigurableKitOption с JSON атрибутами...")
try:
# Получаем первый комплект или создаём тестовый
kit = ProductKit.objects.filter(name__icontains="тест").first()
if not kit:
kit = ProductKit.objects.first()
if not kit:
print(" ⚠️ В базе нет ProductKit, пропускаем этот тест")
kit = None
if kit:
print(f" Используем существующий комплект: {kit.name}")
# Проверяем есть ли уже вариант для этого комплекта
option = ConfigurableKitOption.objects.filter(
parent=configurable,
kit=kit
).first()
if option:
print(f" Вариант уже существует, обновляю атрибуты...")
# Обновляем существующий
option.attributes = {"length": "60", "color": "red"}
option.save()
print(f" ✅ Обновлены атрибуты: {option.attributes}")
else:
# Создаём новый вариант с JSON атрибутами
option = ConfigurableKitOption.objects.create(
parent=configurable,
kit=kit,
attributes={"length": "60", "color": "red"},
is_default=True
)
print(f" ✅ Создан вариант с JSON атрибутами:")
print(f" - Parent: {option.parent.name}")
print(f" - Kit: {option.kit.name}")
print(f" - Attributes (JSON): {option.attributes}")
print(f" - Type: {type(option.attributes)}")
except Exception as e:
print(f" ❌ Ошибка: {e}")
import traceback
traceback.print_exc()
exit(1)
# Проверка 3: Получение и работа с JSON атрибутами
print("\n3⃣ Проверка получения JSON атрибутов из БД...")
try:
options = ConfigurableKitOption.objects.filter(parent=configurable)
print(f" Найдено {options.count()} вариант(ов)")
for idx, opt in enumerate(options, 1):
print(f"\n Вариант {idx}:")
print(f" - ID: {opt.id}")
print(f" - SKU комплекта: {opt.kit.sku}")
print(f" - Атрибуты (JSON): {opt.attributes}")
print(f" - Тип данных: {type(opt.attributes)}")
# Проверяем доступ к ключам JSON
if opt.attributes:
if isinstance(opt.attributes, dict):
print(f" - Доступ к ключам JSON:")
for key, value in opt.attributes.items():
print(f"{key}: {value}")
print(f" ✅ JSON работает корректно!")
else:
print(f" ❌ Атрибуты не являются dict!")
except Exception as e:
print(f" ❌ Ошибка: {e}")
import traceback
traceback.print_exc()
exit(1)
# Проверка 4: Фильтрация по JSON атрибутам (PostgreSQL)
print("\n4⃣ Проверка фильтрации по JSON атрибутам...")
try:
# Попытка использовать JSON фильтрацию (работает в PostgreSQL)
# Для SQLite это может не работать
filtered = ConfigurableKitOption.objects.filter(
parent=configurable,
attributes__length="60"
)
print(f" Попытка фильтрации по attributes__length='60'")
print(f" Найдено результатов: {filtered.count()}")
if filtered.count() > 0:
print(f" ✅ JSON фильтрация работает!")
else:
print(f" JSON фильтрация может не поддерживаться в текущей БД")
except Exception as e:
print(f" JSON фильтрация не поддерживается: {type(e).__name__}")
# Проверка 5: Сложные JSON структуры
print("\n5⃣ Проверка сохранения сложных JSON структур...")
try:
complex_attrs = {
"length": "70",
"color": "white",
"quantity": 15,
"stems": ["rose1", "rose2", "rose3"],
"metadata": {
"fresh": True,
"days_available": 7
}
}
# Обновляем атрибуты сложной структурой
if options.exists():
opt = options.first()
opt.attributes = complex_attrs
opt.save()
# Проверяем что сохранилось правильно
opt_reloaded = ConfigurableKitOption.objects.get(pk=opt.pk)
print(f" ✅ Сохранены сложные JSON атрибуты:")
print(f" {opt_reloaded.attributes}")
# Проверяем вложенность
if opt_reloaded.attributes.get("metadata", {}).get("fresh"):
print(f" ✅ Доступ к вложенным полям JSON работает!")
except Exception as e:
print(f" ❌ Ошибка: {e}")
import traceback
traceback.print_exc()
print("\n" + "=" * 70)
print("ВСЕ ТЕСТЫ ПРОЙДЕНЫ! JSONField работает корректно!")
print("=" * 70)