Added multiple file upload for chart files

This commit is contained in:
apheyhys 2025-05-18 16:37:49 +03:00
parent c9243c7b06
commit d04a549469
2 changed files with 92 additions and 11 deletions

View file

@ -176,6 +176,23 @@ class CaseColorsInline(admin.TabularInline):
return formset
class FrequencyResponseInline(admin.StackedInline):
model = FrequencyResponse
extra = 1
fields = ('file', 'author', 'source_link', 'is_primary', 'notes', 'file_preview')
readonly_fields = ('file_preview',)
def file_preview(self, obj):
if obj.file:
return format_html(
'<a href="{}" target="_blank">{}</a>',
obj.file.url,
os.path.basename(obj.file.name)
)
return "-"
file_preview.short_description = "Файл"
@admin.register(Headphones)
class HeadphonesAdmin(admin.ModelAdmin):
form = HeadphonesAdminForm
@ -209,7 +226,7 @@ class HeadphonesAdmin(admin.ModelAdmin):
'fields': [
('impedance', 'sensitivity'),
'frequency_range',
('frequency_response_chart', 'frequency_response_chart_author', 'frequency_response_chart_link'),
# ('frequency_response_chart', 'frequency_response_chart_author', 'frequency_response_chart_link'),
('microphone', 'noise_cancellation'),
'ip_rating',
]
@ -228,7 +245,7 @@ class HeadphonesAdmin(admin.ModelAdmin):
}),
]
inlines = [HeadphonesDriverInline, HeadphonesImagesInline, CaseColorsInline]
inlines = [HeadphonesDriverInline, HeadphonesImagesInline, CaseColorsInline, FrequencyResponseInline]
# Методы для отображения
def get_reviews_count(self, obj):
@ -421,7 +438,6 @@ class AudioCodecAdmin(admin.ModelAdmin):
# ======================
# Регистрация разъемов и подключений
# ======================
@admin.register(CableConnectionType)
class CableConnectionTypeAdmin(admin.ModelAdmin):
list_display = ('name', 'is_detachable')
@ -464,6 +480,7 @@ class ChargingInterfaceAdmin(admin.ModelAdmin):
# Регистрация отзывов и медиа
# ======================
@admin.register(HeadphonesReviewType)
class HeadphonesReviewTypeAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')

View file

@ -24,7 +24,10 @@ def upload_to_case_image(instance, filename):
return f"headphones/{instance.headphones.id}/case_images/{instance.slug}.{ext}"
def upload_to_frequency_response(instance, filename):
return f"headphones/{instance.headphones.id}/frequency_response/{filename}"
"""Путь для сохранения: headphones/<headphones_id>/frequency_response/<filename>"""
ext = filename.split('.')[-1]
unique_filename = f"{uuid.uuid4().hex}.{ext}"
return f"headphones/{instance.headphones.id}/frequency_response/{unique_filename}"
# ======================
# Базовые справочники
@ -639,6 +642,67 @@ class HeadphonesCaseIP(models.Model):
return self.code
class FrequencyResponse(models.Model):
headphones = models.ForeignKey(
'Headphones',
on_delete=models.CASCADE,
related_name='frequency_responses',
verbose_name="Наушники"
)
file = models.FileField(
upload_to=upload_to_frequency_response,
verbose_name="Файл АЧХ"
)
author = models.CharField(
max_length=100,
verbose_name="Автор измерения",
blank=True,
null=True
)
source_link = models.URLField(
verbose_name="Ссылка на источник",
blank=True,
null=True
)
notes = models.TextField(
verbose_name="Примечания",
blank=True,
null=True
)
is_primary = models.BooleanField(
default=False,
verbose_name="Основная АЧХ"
)
class Meta:
verbose_name = "АЧХ наушников"
verbose_name_plural = "АЧХ наушников"
ordering = ['-is_primary', 'headphones__model']
def __str__(self):
return f"АЧХ {self.headphones.model} ({self.author or 'без автора'})"
def save(self, *args, **kwargs):
if self.is_primary:
# Снимаем флаг is_primary у других АЧХ этих наушников
FrequencyResponse.objects.filter(
headphones=self.headphones
).exclude(
pk=self.pk
).update(is_primary=False)
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
"""Удаление файла при удалении записи"""
if self.file:
try:
if default_storage.exists(self.file.name):
default_storage.delete(self.file.name)
except Exception as e:
print(f"Ошибка при удалении файла АЧХ: {e}")
super().delete(*args, **kwargs)
# ======================
# Основная модель наушников
# ======================
@ -711,13 +775,13 @@ class Headphones(models.Model):
)
# Технические характеристики
frequency_response_chart = models.FileField(
verbose_name="АЧХ (CSV)",
upload_to = upload_to_frequency_response,
null=True,
blank=True,
help_text="Данные в формате [{'frequency': 20, 'amplitude': -2.5}, ...]"
)
# frequency_response_chart = models.FileField(
# verbose_name="АЧХ (CSV)",
# upload_to = upload_to_frequency_response,
# null=True,
# blank=True,
# help_text="Данные в формате [{'frequency': 20, 'amplitude': -2.5}, ...]"
# )
frequency_response_chart_author = models.CharField(
verbose_name="Автор АЧХ",