Files
octopus/myproject/products/models/attributes.py
Andrey Smakotin 79ff523adb Рефакторинг системы вариативных товаров и справочник атрибутов
Основные изменения:
- Переименование ConfigurableKitProduct → ConfigurableProduct
- Добавлена поддержка Product как варианта (не только ProductKit)
- Создан справочник атрибутов (ProductAttribute, ProductAttributeValue)
- CRUD для управления атрибутами с inline редактированием значений
- Пересозданы миграции с нуля для всех приложений
- Добавлена ссылка на атрибуты в навигацию

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 01:44:34 +03:00

117 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
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.
"""
Модели для справочника атрибутов товаров.
Используется для создания переиспользуемых атрибутов (Длина стебля, Цвет, Размер и т.д.)
"""
from django.db import models
from django.utils.text import slugify
from unidecode import unidecode
class ProductAttribute(models.Model):
"""
Справочник атрибутов для вариативных товаров.
Примеры: Длина стебля, Цвет, Размер, Упаковка.
"""
name = models.CharField(
max_length=100,
unique=True,
verbose_name="Название",
help_text="Например: Длина стебля, Цвет, Размер"
)
slug = models.SlugField(
max_length=100,
unique=True,
blank=True,
verbose_name="Slug",
help_text="Автоматически генерируется из названия"
)
description = models.TextField(
blank=True,
verbose_name="Описание",
help_text="Опциональное описание атрибута"
)
position = models.PositiveIntegerField(
default=0,
verbose_name="Позиция",
help_text="Порядок отображения в списке"
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="Дата создания"
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="Дата обновления"
)
class Meta:
verbose_name = "Атрибут товара"
verbose_name_plural = "Атрибуты товаров"
ordering = ['position', 'name']
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(unidecode(self.name))
super().save(*args, **kwargs)
@property
def values_count(self):
"""Количество значений у атрибута"""
return self.values.count()
class ProductAttributeValue(models.Model):
"""
Значения атрибутов.
Примеры для атрибута "Длина стебля": 50, 60, 70, 80.
"""
attribute = models.ForeignKey(
ProductAttribute,
on_delete=models.CASCADE,
related_name='values',
verbose_name="Атрибут"
)
value = models.CharField(
max_length=100,
verbose_name="Значение",
help_text="Например: 50, 60, 70 (для длины) или Красный, Белый (для цвета)"
)
slug = models.SlugField(
max_length=100,
blank=True,
verbose_name="Slug"
)
position = models.PositiveIntegerField(
default=0,
verbose_name="Позиция",
help_text="Порядок отображения в списке значений"
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="Дата создания"
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="Дата обновления"
)
class Meta:
verbose_name = "Значение атрибута"
verbose_name_plural = "Значения атрибутов"
ordering = ['position', 'value']
unique_together = ['attribute', 'value']
indexes = [
models.Index(fields=['attribute', 'position']),
]
def __str__(self):
return f"{self.attribute.name}: {self.value}"
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(unidecode(self.value))
super().save(*args, **kwargs)