Files
santeh-ray/items/models.py
Azimkin af129309ab
All checks were successful
Build and Push Docker Image / build (push) Successful in 26s
feat: replace color field with colors ManyToManyField in items model
- Updated `Item` model to use a ManyToManyField for colors, replacing the old ForeignKey relationship
- Modified templates to handle multiple color swatches in product details
- Updated admin for managing colors with `filter_horizontal`
- Adjusted views to prefetch related `colors` data for items
- Added migration to apply database changes
2026-05-26 00:20:29 +02:00

129 lines
4.5 KiB
Python
Raw 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 decimal import Decimal
from django.db import models
from django.core.exceptions import ValidationError
class Color(models.Model):
name = models.CharField(max_length=100, verbose_name='Название цвета')
hex_code = models.CharField(max_length=7, verbose_name='Цвет (HEX)', help_text='Например, #FF5500')
class Meta:
ordering = ('name',)
verbose_name = 'Цвет'
verbose_name_plural = 'Цвета'
def __str__(self):
return f'{self.name} ({self.hex_code})'
class Category(models.Model):
name = models.CharField(max_length=255, verbose_name='Название')
slug = models.SlugField(unique=True, verbose_name='URL')
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
def __str__(self):
return self.name
class Subcategory(models.Model):
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name='subcategories',
verbose_name='Категория',
)
name = models.CharField(max_length=255, verbose_name='Название')
slug = models.SlugField(verbose_name='URL')
class Meta:
ordering = ('category__name', 'name')
constraints = [
models.UniqueConstraint(
fields=('category', 'slug'),
name='unique_subcategory_slug_per_category',
)
]
verbose_name = 'Подкатегория'
verbose_name_plural = 'Подкатегории'
def __str__(self):
return self.name
class Item(models.Model):
name = models.CharField(max_length=255, verbose_name='Название')
slug = models.SlugField(unique=True, verbose_name='URL')
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='items', verbose_name='Категория')
subcategory = models.ForeignKey(
Subcategory,
on_delete=models.SET_NULL,
related_name='items',
null=True,
blank=True,
verbose_name='Подкатегория',
)
description = models.TextField(blank=True, verbose_name='Описание')
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Цена')
discount_price = models.DecimalField(
max_digits=10, decimal_places=2,
null=True, blank=True,
verbose_name='Цена со скидкой',
)
is_available = models.BooleanField(default=True, verbose_name='В наличии')
is_new = models.BooleanField(default=False, verbose_name='Новинка')
colors = models.ManyToManyField(
'Color',
blank=True,
related_name='items',
verbose_name='Цвета',
)
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 = 'Товары'
def __str__(self):
return self.name
def clean(self):
super().clean()
if self.subcategory_id and self.category_id and self.subcategory.category_id != self.category_id:
raise ValidationError({
'subcategory': 'Подкатегория должна относиться к выбранной категории.'
})
@property
def primary_image(self):
return next(iter(self.images.all()), None)
@property
def display_price(self) -> Decimal:
return self.discount_price if self.discount_price is not None else self.price
@property
def has_discount(self) -> bool:
return self.discount_price is not None
class ItemImage(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, related_name='images', verbose_name='Товар')
image = models.ImageField(upload_to='items/', verbose_name='Изображение')
alt = models.CharField(max_length=255, blank=True, verbose_name='Alt-текст')
sort_order = models.PositiveIntegerField(default=0, verbose_name='Порядок')
is_primary = models.BooleanField(default=False, verbose_name='Главное изображение')
class Meta:
ordering = ('-is_primary', 'sort_order', 'id')
verbose_name = 'Изображение товара'
verbose_name_plural = 'Изображения товара'
def __str__(self):
return self.alt or f'Изображение товара {self.item.name}'