Files
santeh-ray/items/models.py
Azimkin 27187c5e53
All checks were successful
Build and Push Docker Image / build (push) Successful in 30s
feat: add subcategory support for catalog and admin
- Introduced `Subcategory` model with migration and unique slug constraint per category
- Enabled subcategory assignment for items with validation to ensure category matching
- Updated catalog views to handle subcategories, filtering items accordingly
- Enhanced templates (`index.html`, `side-bar.html`, `item-list.html`, `detail.html`) to display subcategories
- Added dynamic subcategory dropdown in Django admin with category filtering
- Created JavaScript for admin subcategory handling and AJAX population
- Wrote comprehensive tests for subcategory functionality in views and admin
2026-04-26 22:53:45 +02:00

94 lines
3.4 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 django.db import models
from django.core.exceptions import ValidationError
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='Цена')
is_available = models.BooleanField(default=True, 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)
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}'