Added image in case color
This commit is contained in:
parent
f4f7790f81
commit
2a83135234
2 changed files with 123 additions and 22 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue