2016-06-24 63 views
3

被上傳到的ImageField我切換到SVG圖像來表示對我的電子商務平臺類別。我是在分類模型使用models.ImageField之前存儲的圖像,但該forms.ImageField驗證是不能夠處理基於矢量的圖像(因此拒絕它)。允許SVG文件通過Django管理

我不要求對有害文件徹底的驗證,因爲所有上傳將通過Django管理來實現。看起來我不得不在我的模型中切換到models.FileField,但我確實需要警告上傳無效圖像。

Nick Khlestov在django-rest-framework's ImageField上寫了SVGAndImageFormField(在文章中找到源文件,我沒有足夠聲望發佈更多鏈接)。如何通過Django的ImageField(而不是DRF)使用此解決方案?

+1

的ImageField的和FileField字段之間的基本區別在於,首先檢查文件是否使用枕頭的圖像,並提供了幾個屬性的可能無關你(高度,寬度)。 FileField不適合您的需求嗎? https://github.com/django/django/blob/master/django/db/models/fields/files.py – Wtower

+0

@Wower我寧願如果它不讓非圖像格式通過。 –

回答

2

原來SVGAndImageFormField對DRF的ImageField沒有依賴關係,它只增加了django.forms.ImageField所做的驗證。

所以接受SVGs在Django管理我改變模型的ImageFieldFileField指定的覆蓋如下:

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) 

現在接受所有之前的圖像格式與SVG一起。

編輯:剛剛發現,即使您不從models.ImageField切換到models.FileField,這項工作。的models.ImageFieldheightwidth屬性仍將光柵圖像類型的工作,並會被設置爲None爲SVG。

+1

可能對某人有用。僅在django 1.9中可用的meta表單中的field_classes,對於那些使用舊版本的用戶,您需要在表單中明確定義字段。 –

2

我從來沒有使用SVGAndImageFormField所以我真的不能作出評論。就個人而言,我會選擇一個簡單的FileField應用程序,但這顯然取決於項目要求。我將擴大對如下:

正如評論所說,一個ImageField的和FileField字段之間的基本區別在於,首先檢查文件是否使用枕頭的圖像:

繼承所有屬性和來自FileField的方法,但也驗證上傳的對象是有效的圖像。

參考:Django docsDjango source code

它還提供了幾個屬性可能無關的情況下SVG(高度,寬度)的。

因此,模型領域可能是:

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

您可以使用像is_svg函數,如在相關問題提供:

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

然後一個函數來驗證SVG:

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

感謝您的回答,這幾乎是'SVGAndImageFormField'所做的。 –

1

這裏是可以作爲一個簡單的模型領域的解決方案,就可以把代替models.ImageField

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

你需要在你的代碼某處定義以下類和功能:

from django.db import models 

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

這裏是如何SVGAndImageFieldForm樣子:

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 

功能validate_svg我從其他的解決方案了:

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 

另外,如果你想使用SVG文件只模型場 - 你可以做到這一點更簡單。

只需創建類,繼承自models.FileField,並在__init__方法中您可以將validate_svg函數添加到kwargs['validators']

或者只是添加這個驗證程序models.FileField和快樂:)