Added multiple file upload for chart files
This commit is contained in:
parent
c9243c7b06
commit
d04a549469
2 changed files with 92 additions and 11 deletions
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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="Автор АЧХ",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue