Django: Image upload issue
Python: 3.5
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.
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.
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.
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
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(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.
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 = '{}.{}'.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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With