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(
+ ''.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")