Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: PIL image upload from form issue

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
like image 674
Issac Gable Avatar asked Jan 30 '26 14:01

Issac Gable


1 Answers

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
like image 84
Issac Gable Avatar answered Feb 02 '26 03:02

Issac Gable



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!