feat: replace color field with colors ManyToManyField in items model
All checks were successful
Build and Push Docker Image / build (push) Successful in 26s
All checks were successful
Build and Push Docker Image / build (push) Successful in 26s
- 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
This commit is contained in:
@@ -59,7 +59,8 @@ class ItemAdmin(admin.ModelAdmin):
|
|||||||
form = ItemAdminForm
|
form = ItemAdminForm
|
||||||
save_as = True
|
save_as = True
|
||||||
list_display = ('name', 'category', 'subcategory', 'price', 'discount_price', 'is_new', 'is_available', 'created_at')
|
list_display = ('name', 'category', 'subcategory', 'price', 'discount_price', 'is_new', 'is_available', 'created_at')
|
||||||
list_filter = ('is_available', 'is_new', 'color', 'category', 'subcategory', 'created_at')
|
list_filter = ('is_available', 'is_new', 'colors', 'category', 'subcategory', 'created_at')
|
||||||
|
filter_horizontal = ('colors',)
|
||||||
prepopulated_fields = {'slug': ('name',)}
|
prepopulated_fields = {'slug': ('name',)}
|
||||||
inlines = (ItemImageInline,)
|
inlines = (ItemImageInline,)
|
||||||
|
|
||||||
|
|||||||
22
items/migrations/0005_remove_item_color_item_colors.py
Normal file
22
items/migrations/0005_remove_item_color_item_colors.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 6.0.5 on 2026-05-25 22:17
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('items', '0004_color_item_discount_price_item_is_new_item_color'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='item',
|
||||||
|
name='color',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='colors',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='items', to='items.color', verbose_name='Цвета'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -75,12 +75,11 @@ class Item(models.Model):
|
|||||||
)
|
)
|
||||||
is_available = models.BooleanField(default=True, verbose_name='В наличии')
|
is_available = models.BooleanField(default=True, verbose_name='В наличии')
|
||||||
is_new = models.BooleanField(default=False, verbose_name='Новинка')
|
is_new = models.BooleanField(default=False, verbose_name='Новинка')
|
||||||
color = models.ForeignKey(
|
colors = models.ManyToManyField(
|
||||||
'Color',
|
'Color',
|
||||||
on_delete=models.SET_NULL,
|
blank=True,
|
||||||
null=True, blank=True,
|
|
||||||
related_name='items',
|
related_name='items',
|
||||||
verbose_name='Цвет',
|
verbose_name='Цвета',
|
||||||
)
|
)
|
||||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')
|
||||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='Дата обновления')
|
updated_at = models.DateTimeField(auto_now=True, verbose_name='Дата обновления')
|
||||||
|
|||||||
@@ -260,8 +260,8 @@ def index(request: HttpRequest, category: str | None = None) -> HttpResponse:
|
|||||||
def detail(request: HttpRequest, category: str, slug: str) -> HttpResponse:
|
def detail(request: HttpRequest, category: str, slug: str) -> HttpResponse:
|
||||||
try:
|
try:
|
||||||
item = (
|
item = (
|
||||||
Item.objects.select_related('category', 'subcategory', 'color')
|
Item.objects.select_related('category', 'subcategory')
|
||||||
.prefetch_related('images')
|
.prefetch_related('images', 'colors')
|
||||||
.get(category__slug=category.lower(), slug=slug)
|
.get(category__slug=category.lower(), slug=slug)
|
||||||
)
|
)
|
||||||
except Item.DoesNotExist:
|
except Item.DoesNotExist:
|
||||||
|
|||||||
@@ -56,16 +56,19 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if item.color %}
|
{% with colors=item.colors.all %}
|
||||||
<div class="product-summary__swatches" aria-label="Цвет товара">
|
{% if colors %}
|
||||||
<span
|
<div class="product-summary__swatches" aria-label="Цвета товара">
|
||||||
class="product-summary__swatch product-summary__swatch--active"
|
{% for color in colors %}
|
||||||
style="background: {{ item.color.hex_code }};"
|
<span
|
||||||
title="{{ item.color.name }}"
|
class="product-summary__swatch"
|
||||||
></span>
|
style="background: {{ color.hex_code }};"
|
||||||
<span class="product-summary__color-name">{{ item.color.name }}</span>
|
title="{{ color.name }}"
|
||||||
|
></span>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
{% if item.description %}
|
{% if item.description %}
|
||||||
<div class="product-summary__description">{{ item.description|linebreaksbr }}</div>
|
<div class="product-summary__description">{{ item.description|linebreaksbr }}</div>
|
||||||
@@ -101,3 +104,11 @@
|
|||||||
|
|
||||||
{% include "_fragments/footer.html" %}
|
{% include "_fragments/footer.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block add_js %}
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
Fancybox.bind('[data-fancybox="product-gallery"]');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user