Allow SVG club logos

ImageField validates uploads through Pillow, which can't read SVGs, so
a club crest that's a vector logo was rejected outright. Switches to a
plain FileField with an extension allowlist (png/jpg/jpeg/gif/webp/svg)
instead, and restricts the file picker to image types via the widget's
accept attribute.
This commit is contained in:
2026-07-27 10:27:07 +02:00
parent 075c2918b6
commit 88a6c63f9f
3 changed files with 31 additions and 2 deletions

View File

@@ -0,0 +1,20 @@
# Generated by Django 6.0.6 on 2026-07-24 16:40
import club.models
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('club', '0014_club_secondary_color'),
]
operations = [
migrations.AlterField(
model_name='club',
name='logo',
field=models.FileField(blank=True, help_text="Shown on the club's own pages. Without one, the club's initials are used.", upload_to=club.models.club_logo_path, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'])], verbose_name='logo'),
),
]

View File

@@ -1,6 +1,6 @@
import datetime import datetime
from django.core.validators import RegexValidator from django.core.validators import FileExtensionValidator, RegexValidator
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@@ -31,7 +31,15 @@ class Club(UUIDModel):
name = models.CharField(_("name"), max_length=255) name = models.CharField(_("name"), max_length=255)
slug = models.SlugField(_("slug"), max_length=255, unique=True, blank=True, help_text=_("Drives subdomain / path resolution (e.g. ajax-united.rosterchief.app).")) slug = models.SlugField(_("slug"), max_length=255, unique=True, blank=True, help_text=_("Drives subdomain / path resolution (e.g. ajax-united.rosterchief.app)."))
logo = models.ImageField(_("logo"), upload_to=club_logo_path, blank=True, help_text=_("Shown on the club's own pages. Without one, the club's initials are used.")) logo = models.FileField(
_("logo"),
upload_to=club_logo_path,
blank=True,
# A plain FileField, not ImageField: Pillow (which ImageField validates through)
# cannot read SVGs, and club crests are commonly vector logos.
validators=[FileExtensionValidator(allowed_extensions=["png", "jpg", "jpeg", "gif", "webp", "svg"])],
help_text=_("Shown on the club's own pages. Without one, the club's initials are used."),
)
primary_color = models.CharField( primary_color = models.CharField(
_("primary colour"), _("primary colour"),
max_length=7, max_length=7,

View File

@@ -21,6 +21,7 @@ class ClubForm(forms.ModelForm):
widgets = { widgets = {
"primary_color": forms.TextInput(attrs={"placeholder": "#1e40af"}), "primary_color": forms.TextInput(attrs={"placeholder": "#1e40af"}),
"secondary_color": forms.TextInput(attrs={"placeholder": "#be185d"}), "secondary_color": forms.TextInput(attrs={"placeholder": "#be185d"}),
"logo": forms.ClearableFileInput(attrs={"accept": "image/png,image/jpeg,image/gif,image/webp,image/svg+xml"}),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):