Added image in case color

This commit is contained in:
apheyhys 2025-05-04 17:35:18 +03:00
parent f4f7790f81
commit 2a83135234
2 changed files with 123 additions and 22 deletions

View file

@ -146,6 +146,34 @@ class HeadphonesDriverInline(admin.TabularInline):
autocomplete_fields = ['driver']
# class HeadphonesColorInline(admin.TabularInline):
# model = Headphones.colors.through # Используем автоматическую промежуточную модель
# extra = 1
# # autocomplete_fields = ['casecolors'] # Убедитесь, что это правильное имя related_name
# verbose_name = "Доступный цвет"
# verbose_name_plural = "Доступные цвета"
class CaseColorsInline(admin.TabularInline):
model = CaseColors
extra = 1
fields = ('name_ru', 'name_en', 'image', 'image_preview', 'slug')
readonly_fields = ('image_preview', 'slug')
def image_preview(self, obj):
if obj.image:
return format_html('<img src="{}" width="50" height="50" />', obj.image.url)
return "Нет изображения"
image_preview.short_description = "Превью"
def get_formset(self, request, obj=None, **kwargs):
formset = super().get_formset(request, obj, **kwargs)
# Устанавливаем начальное значение для slug, если объект новый
if obj and not obj.pk:
formset.form.base_fields['slug'].initial = f"{obj.model}_"
return formset
@admin.register(Headphones)
class HeadphonesAdmin(admin.ModelAdmin):
form = HeadphonesAdminForm
@ -154,7 +182,7 @@ class HeadphonesAdmin(admin.ModelAdmin):
list_filter = ('brand', 'connection_type', 'published', 'case_type')
search_fields = ('model', 'brand__name', 'description')
prepopulated_fields = {'slug': ('brand', 'model')}
filter_horizontal = ('tags', 'colors')
filter_horizontal = ('tags',)
list_editable = ('published',)
actions = ['make_published', 'make_unpublished']
readonly_fields = (
@ -186,7 +214,7 @@ class HeadphonesAdmin(admin.ModelAdmin):
}),
('Внешний вид', {
'fields': [
'colors',
# 'colors',
('weight', 'release_year')
]
}),
@ -198,7 +226,7 @@ class HeadphonesAdmin(admin.ModelAdmin):
}),
]
inlines = [HeadphonesDriverInline, HeadphonesImagesInline]
inlines = [HeadphonesDriverInline, HeadphonesImagesInline, CaseColorsInline]
# Методы для отображения
def get_reviews_count(self, obj):
@ -223,10 +251,11 @@ class HeadphonesAdmin(admin.ModelAdmin):
driver_configuration_display.short_description = 'Конфигурация драйверов'
def get_inline_instances(self, request, obj=None):
inlines = [
HeadphonesDriverInline(self.model, self.admin_site),
HeadphonesImagesInline(self.model, self.admin_site)
]
# inlines = [
# HeadphonesDriverInline(self.model, self.admin_site),
# HeadphonesImagesInline(self.model, self.admin_site)
# ]
inlines = super().get_inline_instances(request, obj)
if obj:
if obj.connection_type == 'wired':
@ -288,8 +317,28 @@ class BrandCountryAdmin(admin.ModelAdmin):
@admin.register(CaseColors)
class CaseColorsAdmin(admin.ModelAdmin):
list_display = ('name', 'hex_code')
search_fields = ('name',)
list_display = ('name_ru', 'name_en', 'headphones', 'image_preview', 'slug')
list_filter = ('headphones__brand',)
search_fields = ('name_ru', 'name_en', 'headphones__model')
readonly_fields = ('image_preview', 'slug')
list_select_related = ('headphones', 'headphones__brand')
fieldsets = [
('Основная информация', {
'fields': ['headphones', 'name_ru', 'name_en', 'slug']
}),
('Изображение', {
'fields': ['image', 'image_preview']
})
]
def get_queryset(self, request):
return super().get_queryset(request).select_related('headphones__brand')
def save_model(self, request, obj, form, change):
if not obj.slug:
obj.slug = slugify(f"{obj.headphones.model}_{obj.name_en}")
super().save_model(request, obj, form, change)
@admin.register(CaseType)

View file

@ -18,6 +18,11 @@ from PIL import Image
def upload_to(instance, filename):
return f"headphones/{instance.product.id}/{filename}"
def upload_to_case_image(instance, filename):
"""Путь для сохранения: headphones/<product_id>/case_images/<slug>.<ext>"""
ext = filename.split('.')[-1]
return f"headphones/{instance.headphones.id}/case_images/{instance.slug}.{ext}"
# ======================
# Базовые справочники
# ======================
@ -33,16 +38,45 @@ class BrandCountry(models.Model):
class CaseColors(models.Model):
name = models.CharField(max_length=50, verbose_name="Название цвета")
hex_code = models.CharField(max_length=50, verbose_name="HEX-код цвета")
headphones = models.ForeignKey(
'Headphones',
on_delete=models.CASCADE,
related_name='case_colors',
verbose_name='Наушники'
)
name_ru = models.CharField('Название цвета (рус)', max_length=100)
name_en = models.CharField('Название цвета (англ)', max_length=100)
slug = models.SlugField(max_length=150, unique=True, blank=True, verbose_name="URL-идентификатор")
image = models.ImageField('Изображение', upload_to=upload_to_case_image)
class Meta:
verbose_name = "Цвет корпуса"
verbose_name_plural = "Цвета корпусов"
def save(self, *args, **kwargs):
if not self.slug:
# Генерируем slug в формате "модельнаушников_цветангл"
base_slug = slugify(f"{self.headphones.model}_{self.name_en}")
self.slug = base_slug
# Проверяем уникальность slug
counter = 1
while CaseColors.objects.filter(slug=self.slug).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs)
def image_preview(self):
if self.image:
return format_html('<img src="{}" width="50" height="50" />', self.image.url)
return "Нет изображения"
image_preview.short_description = 'Превью'
image_preview.allow_tags = True
def __str__(self):
return f"{self.name} {self.hex_code}"
return f"{self.name_ru} ({self.headphones.model})"
class Meta:
verbose_name = 'Цвет корпуса'
verbose_name_plural = 'Цвета корпусов'
ordering = ['headphones__model', 'name_ru']
# ======================
# Основные модели брендов и категорий
@ -212,7 +246,15 @@ class Driver(models.Model):
verbose_name_plural = "Драйверы"
def __str__(self):
return f"{self.driver_type.name} {self.size}mm"
parts = [self.driver_type.name]
if self.driver_model:
parts.append(self.driver_model.name)
if self.size:
parts.append(f"{self.size}mm")
return " ".join(parts)
class NoiseCancellationType(models.Model):
@ -701,12 +743,13 @@ class Headphones(models.Model):
blank=True
)
# Внешний вид и физические параметры
colors = models.ManyToManyField(
CaseColors,
related_name='headphones',
verbose_name="Цвета"
)
# # Внешний вид и физические параметры
# colors = models.ManyToManyField(
# CaseColors,
# related_name='headphones',
# blank=True,
# verbose_name="Доступные цвета"
# )
weight = models.PositiveSmallIntegerField(
verbose_name="Вес (г)",
null=True,
@ -742,6 +785,15 @@ class Headphones(models.Model):
self.slug = slugify(f"{self.brand.name} {self.model}")
super().save(*args, **kwargs)
# Обновляем slug для связанных цветов, если изменилась модель
if self.pk and hasattr(self, 'case_colors'):
for color in self.case_colors.all():
new_slug = slugify(f"{self.model}_{color.name_en}")
if color.slug != new_slug:
color.slug = new_slug
color.save()
class HeadphonesConnector(models.Model):
headphones = models.ForeignKey(
'Headphones',