diff --git a/backend/project/observations/admin.py b/backend/project/observations/admin.py index 3014701..9d20b34 100644 --- a/backend/project/observations/admin.py +++ b/backend/project/observations/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.contrib.gis.admin import GISModelAdmin from django.utils.safestring import mark_safe +from django.utils.translation import gettext_lazy as _ from sorl.thumbnail import get_thumbnail from project.observations.models import ( @@ -18,6 +19,7 @@ class SubTypeInline(admin.TabularInline): fields = ("label", "description", "pictogram", "picto_preview") readonly_fields = ("picto_preview",) + @admin.display(description=_("Preview")) def picto_preview(self, obj): # ex. the name of column is "image" if obj.pictogram: @@ -64,7 +66,33 @@ class ObservationTypeAdmin(admin.ModelAdmin): search_fields = ("label", "description") ordering = ("label",) inlines = [SubTypeInline] + readonly_fields = ("picto_preview",) + fieldsets = ( + ( + None, + { + "fields": ( + ( + "label", + "description", + ), + ) + }, + ), + ( + _("Pictogram"), + { + "fields": ( + ( + "picto_preview", + "pictogram", + ), + ) + }, + ), + ) + @admin.display(description=_("Preview")) def picto_preview(self, obj): # ex. the name of column is "image" return mark_safe( @@ -81,10 +109,11 @@ class ObservationSubTypeAdmin(admin.ModelAdmin): list_filter = ("observation_type",) ordering = ("label",) + @admin.display(description=_("Preview")) def picto_preview(self, obj): # ex. the name of column is "image" return mark_safe( - ''.format( + 'picto'.format( obj.pictogram.url ) ) diff --git a/backend/project/observations/migrations/0002_alter_observationsubtype_pictogram_and_more.py b/backend/project/observations/migrations/0002_alter_observationsubtype_pictogram_and_more.py new file mode 100644 index 0000000..3e70bf8 --- /dev/null +++ b/backend/project/observations/migrations/0002_alter_observationsubtype_pictogram_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0.6 on 2024-07-03 15:04 + +import project.utils.db.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("observations", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="observationsubtype", + name="pictogram", + field=project.utils.db.fields.SVGFileField( + upload_to="observation_types", verbose_name="Pictogram" + ), + ), + migrations.AlterField( + model_name="observationtype", + name="pictogram", + field=project.utils.db.fields.SVGFileField( + upload_to="observation_types", verbose_name="Pictogram" + ), + ), + ] diff --git a/backend/project/observations/models.py b/backend/project/observations/models.py index 27d37c9..0e2dfba 100644 --- a/backend/project/observations/models.py +++ b/backend/project/observations/models.py @@ -4,6 +4,7 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic.dates import timezone_today +from project.utils.db.fields import SVGFileField from project.utils.db.mixins import TimeStampMixin @@ -23,9 +24,7 @@ class Meta: class ObservationType(TimeStampMixin): label = models.CharField(max_length=100, unique=True) description = models.TextField(blank=True) - pictogram = models.ImageField( - upload_to="observation_types", verbose_name=_("Pictogram") - ) + pictogram = SVGFileField(upload_to="observation_types", verbose_name=_("Pictogram")) def __str__(self): return self.label @@ -42,9 +41,7 @@ class ObservationSubType(TimeStampMixin): observation_type = models.ForeignKey( ObservationType, on_delete=models.PROTECT, related_name="sub_types" ) - pictogram = models.ImageField( - upload_to="observation_types", verbose_name=_("Pictogram") - ) + pictogram = SVGFileField(upload_to="observation_types", verbose_name=_("Pictogram")) def __str__(self): return f"{self.label} ({self.observation_type})" diff --git a/backend/project/utils/db/fields.py b/backend/project/utils/db/fields.py new file mode 100644 index 0000000..cfe035e --- /dev/null +++ b/backend/project/utils/db/fields.py @@ -0,0 +1,10 @@ +from django.db import models + +from project.utils.db.validators import ( + validate_svg_file_content, + validate_svg_file_extension, +) + + +class SVGFileField(models.FileField): + default_validators = [validate_svg_file_extension, validate_svg_file_content] diff --git a/backend/project/utils/db/validators.py b/backend/project/utils/db/validators.py new file mode 100644 index 0000000..cd7b420 --- /dev/null +++ b/backend/project/utils/db/validators.py @@ -0,0 +1,13 @@ +from django.core.exceptions import ValidationError +from django.core.validators import FileExtensionValidator + + +def validate_svg_file_extension(value): + return FileExtensionValidator(allowed_extensions=["svg"])(value) + + +# write django validator that check if http://www.w3.org/2000/svg is in file content +def validate_svg_file_content(value): + content = str(value.read()) + if "http://www.w3.org/2000/svg" not in content: + raise ValidationError("File is not an SVG file")