2016-06-24 5 views
3

Ich wechsle zu SVG-Bildern, um Kategorien auf meiner E-Commerce-Plattform darzustellen. Ich habe models.ImageField im Category-Modell verwendet, um die Bilder vorher zu speichern, aber die forms.ImageField Validierung ist nicht in der Lage, ein vektorbasiertes Bild zu verarbeiten (und lehnt es daher ab).Erlaube das Hochladen von SVG-Dateien nach ImageField über Django admin

Ich benötige keine gründliche Validierung gegen schädliche Dateien, da alle Uploads über den Django Admin erfolgen. Es sieht so aus, als müsste ich in meinem Modell zu einem models.FileField wechseln, aber ich möchte Warnungen vor dem Hochladen ungültiger Bilder.

Nick Khlestov schrieb eine SVGAndImageFormField (Quelle innerhalb des Artikels finden, ich habe nicht genug Ruf, um weitere Links zu posten) über django-rest-framework's ImageField. Wie verwende ich diese Lösung für Djangos ImageField (und nicht für die DRF-Version)?

+1

Der grundlegende Unterschied zwischen einem Imagefield und einem Filefield ist, dass die erste überprüft, ob eine Datei ist ein Bild Kissen mit und bietet ein paar Attribute möglicherweise irrelevant Sie (Höhe, Breite). Ist kein FileField für Ihre Anforderungen geeignet? https://github.com/django/django/blob/master/django/db/models/fields/files.py – Wtower

+0

@Wtower Ich würde es vorziehen, wenn es keine Nicht-Bildformate durchlässt. –

Antwort

2

Es stellt sich heraus Das SVGAndImageFormField hat keine Abhängigkeiten von DRF ImageField, es fügt nur die Überprüfung von django.forms.ImageField hinzugefügt.

So SVGs in Django Admin ich zu akzeptieren änderte sich die ImageField Modell auf ein FileField und eine Überschreibung wie folgt angegeben:

class MyModelForm(forms.ModelForm): 
    class Meta: 
     model = MyModel 
     exclude = [] 
     field_classes = { 
      'image_field': SVGAndImageFormField, 
     } 

class MyModelAdmin(admin.ModelAdmin): 
    form = MyModelForm 

admin.site.register(MyModel, MyModelAdmin) 

Er akzeptiert nun alle vorherigen Bildformate zusammen mit SVG.

EDIT: Gerade herausgefunden, dass dies funktioniert, auch wenn Sie nicht von models.ImageField zu models.FileField wechseln. Die Attribute height und width von models.ImageField funktionieren weiterhin für Rasterbildtypen und werden für SVG auf None festgelegt.

+1

Kann für jemanden hilfreich sein. field_classes in Meta des Formulars, das nur von django 1.9 verfügbar ist, für diejenigen, die ältere Version verwenden, müssen Sie Feld in Formular explizit definieren. –

2

Ich habe nie SVGAndImageFormField verwendet, also kann ich nicht wirklich dazu kommentieren. Persönlich hätte ich mich für eine einfache Anwendung von FileField entschieden, aber das hängt eindeutig von den Projektanforderungen ab. Ich werde dazu unten erweitern:

Wie im Kommentar erwähnt, ist der grundlegende Unterschied zwischen einem Imagefield und einem Filefield ist, dass die erste überprüft, ob eine Datei ein Bild Kissen mit:

Erbt alle Attribute und Methoden von FileField, validiert aber auch, dass das hochgeladene Objekt ein gültiges Bild ist.

Referenz: Django docs, Django source code

Es bietet auch ein paar Attribute möglicherweise irrelevant für den SVG Fall (Höhe, Breite).

Daher könnte das Modellfeld sein:

svg = models.FileField(upload_to=..., validators=[validate_svg]) 

Sie eine Funktion wie is_svg verwenden können, wie in der jeweiligen Frage zu finden:

How can I say a file is SVG without using a magic number?

Dann wird eine Funktion SVG zu validieren:

def validate_svg(file, valid): 
    if not is_svg(file): 
     raise ValidationError("File not svg") 
+0

Danke für deine Antwort, das ist ziemlich genau was 'SVGAndImageFormField' tut. –

1

Hier ist eine Lösung, die als einfaches Modellfeld arbeitet, dass Sie statt models.ImageField setzen können:

class Icon(models.Model): 
    image_file = SVGAndImageField() 

Sie müssen definieren, folgende Klassen und Funktionen irgendwo im Code:

from django.db import models 

class SVGAndImageField(models.ImageField): 
    def formfield(self, **kwargs): 
     defaults = {'form_class': SVGAndImageFieldForm} 
     defaults.update(kwargs) 
     return super().formfield(**defaults) 

Und hier ist, wie SVGAndImageFieldForm wie folgt aussieht:

from django import forms 
from django.core.exceptions import ValidationError 

class SVGAndImageFieldForm(forms.ImageField): 
    def to_python(self, data): 
     try: 
      f = super().to_python(data) 
     except ValidationError: 
      return validate_svg(data) 

     return f 

Funktion validate_svg ich von anderen Lösungen nahm:

import xml.etree.cElementTree as et 

def validate_svg(f): 
    # Find "start" word in file and get "tag" from there 
    f.seek(0) 
    tag = None 
    try: 
     for event, el in et.iterparse(f, ('start',)): 
      tag = el.tag 
      break 
    except et.ParseError: 
     pass 

    # Check that this "tag" is correct 
    if tag != '{http://www.w3.org/2000/svg}svg': 
     raise ValidationError('Uploaded file is not an image or SVG file.') 

    # Do not forget to "reset" file 
    f.seek(0) 

    return f 

Auch wenn Sie SVG-Dateien nur Modellfeld verwenden möchten - Sie können es einfacher machen.

Erstellen Sie einfach Klasse, geerbt von models.FileField und in __init__ Methode können Sie validate_svg Funktion kwargs['validators'] hinzufügen.

Oder nur diese Prüfung zu models.FileField hinzufügen und glücklich sein :)

Verwandte Themen