Django: PIL图像上传自form issue

时间:2021-12-30 00:25:29

Django: Image upload issue

Django:图片上传的问题

Python: 3.5

Python:3.5

Django: 1.11

Django:1.11

I am writing a simple news app that will take an image as part of the article. I have chosen to modify the image creating a thumbnail to be stored in the form with the clean_(field name) function provided by Django Forms.

我正在编写一个简单的新闻应用程序,它将作为文章的一部分使用图像。我选择修改映像,创建一个缩略图,并使用Django表单提供的clean_(字段名)函数将其存储在表单中。

The issue I am encountering is that after going through the submit and the clean_image function the ImageField validation kicks me back with an error stating that the file extension " is not allowed.

我遇到的问题是,在完成提交和clean_image函数之后,ImageField验证会返回一个错误,指出文件扩展名“不允许”。

I know the issues is coming from the clean_image function after I save the PIL image and then hand it back over to Django ContentFile to process. Any help will be great.

我知道问题来自于clean_image函数,在我保存PIL映像之后,然后将它交给Django ContentFile进行处理。任何帮助都是好的。

Form:

形式:

from django.conf import settings
from django.core.files.base import ContentFile
from django.utils.translation import ugettext_lazy as _
from .models import News
from ironcsd.validators import MimetypeValidator
from datetime import date
from PIL import Image, ImageEnhance
from io import StringIO, BytesIO
import hashlib, mimetypes
import os, io
import logging, logging.config

logger = logging.getLogger(__name__)

class NewsForm(forms.ModelForm):

    class Meta:
        model = News
        widgets = {
            'details': forms.Textarea(attrs={'id': 'smde-editor'}),
        }
        fields = ('title','details','image')


    def clean_image(self):
        image = self.cleaned_data.get('image')
        md5 = hashlib.md5()
        md5.update(repr(image.name).encode('utf-8'))
        file_name = md5.hexdigest()

        if image._size > 30 * 1024 * 1024:
            raise forms.ValidationError(_('File is too big.'), code='invalid')

        image = Image.open(image)

        if image.size[0] < 1024 or image.size[1] < 1024:
            raise forms.ValidationError(_('Your image needs to be at least 1024x1024.'))

        image.thumbnail([1024,1024], Image.ANTIALIAS)
        image_string = io.BytesIO()
        image.save(image_string, image.format)
        image = ContentFile(image_string.getvalue(), file_name)

        return image

Model:

模型:

from django.db import models
from django.urls import reverse, reverse_lazy
from ironcsd.models import Audit

class News(Audit):
    title = models.CharField(max_length=255)
    details = models.TextField()
    image = models.ImageField(upload_to='news/%Y/%m/')

    class Meta:
        verbose_name_plural = "news"

    def __str__(self):
        return self.title

1 个解决方案

#1


1  

So I found the Issue. I was correct in that ContentFile was the issue. In ContentFile you need to provide the io value and a filename.

所以我找到了问题所在。我是对的,内容文件就是问题所在。在ContentFile中,需要提供io值和文件名。

ContentFile(image_io.getvalue(), image_name)

In the image_name you need to insure that the image has the file extensions (bmp, png, gif, etc) so that when converted back into a django object the file can go through proper validation. So the code answer is as follows.

在image_name中,您需要确保映像具有文件扩展名(bmp、png、gif等),以便当将该文件转换回django对象时,可以进行适当的验证。代码答案如下。

I create a hashed filename from the cleaned image's name. Then I created a variable called image_name that took the file_name and added the PIL image format as an extension.

我从已清理的图像的名称创建一个散列文件名。然后我创建了一个名为image_name的变量,它接受file_name并添加PIL图像格式作为扩展。

image_name = '{}.{}'.format(file_name,image.format)

I then used this image_name in my ContentFile which passed a proper file to my form_valid in the view.

然后,我在我的ContentFile中使用了这个image_name,它将一个适当的文件传递给了视图中的form_valid。

Completed Code:

完成代码:

class NewsForm(forms.ModelForm):

    class Meta:
        model = News
        widgets = {
            'details': forms.Textarea(attrs={'id': 'smde-editor'}),
        }
        fields = ('title','details','image')


    def clean_image(self):
        image = self.cleaned_data.get('image')
        md5 = hashlib.md5()
        md5.update(repr(image.name).encode('utf-8'))
        file_name = md5.hexdigest()

        if image._size > 30 * 1024 * 1024:
            raise forms.ValidationError(_('File is too big.'), code='invalid')

        image = Image.open(image)

        if image.size[0] < 1024 or image.size[1] < 1024:
            raise forms.ValidationError(_('Your image needs to be at least 1024x1024.'))

        if image.format not in ('BMP','PNG','JPEG','GIF'):
            raise forms.ValidationError(_("Unsupported image type. Please uplod a bmp, png, jpeg, or gif."), code='invalid')

        image.thumbnail([1024,1024], Image.ANTIALIAS)
        image_io = io.BytesIO()
        image.save(image_io, format=image.format)
        image_name = '{}.{}'.format(file_name,image.format)
        image = ContentFile(image_io.getvalue(), image_name)

        return image

#1


1  

So I found the Issue. I was correct in that ContentFile was the issue. In ContentFile you need to provide the io value and a filename.

所以我找到了问题所在。我是对的,内容文件就是问题所在。在ContentFile中,需要提供io值和文件名。

ContentFile(image_io.getvalue(), image_name)

In the image_name you need to insure that the image has the file extensions (bmp, png, gif, etc) so that when converted back into a django object the file can go through proper validation. So the code answer is as follows.

在image_name中,您需要确保映像具有文件扩展名(bmp、png、gif等),以便当将该文件转换回django对象时,可以进行适当的验证。代码答案如下。

I create a hashed filename from the cleaned image's name. Then I created a variable called image_name that took the file_name and added the PIL image format as an extension.

我从已清理的图像的名称创建一个散列文件名。然后我创建了一个名为image_name的变量,它接受file_name并添加PIL图像格式作为扩展。

image_name = '{}.{}'.format(file_name,image.format)

I then used this image_name in my ContentFile which passed a proper file to my form_valid in the view.

然后,我在我的ContentFile中使用了这个image_name,它将一个适当的文件传递给了视图中的form_valid。

Completed Code:

完成代码:

class NewsForm(forms.ModelForm):

    class Meta:
        model = News
        widgets = {
            'details': forms.Textarea(attrs={'id': 'smde-editor'}),
        }
        fields = ('title','details','image')


    def clean_image(self):
        image = self.cleaned_data.get('image')
        md5 = hashlib.md5()
        md5.update(repr(image.name).encode('utf-8'))
        file_name = md5.hexdigest()

        if image._size > 30 * 1024 * 1024:
            raise forms.ValidationError(_('File is too big.'), code='invalid')

        image = Image.open(image)

        if image.size[0] < 1024 or image.size[1] < 1024:
            raise forms.ValidationError(_('Your image needs to be at least 1024x1024.'))

        if image.format not in ('BMP','PNG','JPEG','GIF'):
            raise forms.ValidationError(_("Unsupported image type. Please uplod a bmp, png, jpeg, or gif."), code='invalid')

        image.thumbnail([1024,1024], Image.ANTIALIAS)
        image_io = io.BytesIO()
        image.save(image_io, format=image.format)
        image_name = '{}.{}'.format(file_name,image.format)
        image = ContentFile(image_io.getvalue(), image_name)

        return image