2

I want to get the value of a CharField based on the value of an ImageField. My form and view are defined as:

#Form
class GpsImForm(forms.Form):
    image = forms.ImageField(required=True)
    gps_data = forms.CharField(required=True)

#View
def gpsim_gen_view(request):
    if request.method == 'POST':
        form = GpsImForm(request.POST, request.FILES)
        if 'image' in request.FILES:
            im = request.FILES['image']
            i = Image.open(im)
            ... # functions to extract exif data from i
            request.POST.update({ 'gps_data': ...}) # set gps_data based on exif data from i
        if form.is_valid():
            obj = form.save()
            return ... #returns the gpsim
    else:
        form = GpsImForm()
    return direct_to_template(request, 'gpsim_generate.html', {'form': form,})

The gps_data is updated, but, as soon as I use Image.open(), I get the following error message:

Upload a valid image. The file you uploaded was either not an image or a corrupted image.

If I comment the lines concerning i and modify the gps_data to whatever, the form (with the image) is saved without any error...

# i = Image.open(im)
# ...
# functions to extract exif data from i
request.POST.update({ 'gps_data': 'some text'}) # set gps_data to 'test'
Samuel Parkinson
  • 2,992
  • 1
  • 27
  • 38
gueux
  • 323
  • 1
  • 12
  • What type(s) of image have you tried? It's a common problem to have PIL installed without jpeg support, in which case you need to uninstall PIL, install libjpeg, then reinstall PIL. – aganders3 Sep 20 '12 at 14:58
  • Really, the problem was not about libjpeg. As said in the end of question, when I do not use Image.open(), the form (with the image) is saved without any error. Thanks anyway :-) – gueux Sep 20 '12 at 17:04
  • Your question just sounded similar to this one, so I was checking if you had tried with other file types: http://stackoverflow.com/questions/1398701/problems-with-snow-leopard-django-pil – aganders3 Sep 20 '12 at 20:07

2 Answers2

2

first of all, make sure that your form has the enctype tag

<form enctype="multipart/form-data" ... >    

Try to write the img (all the chunks) on disk:

import Image
from random import choice
from django.conf import settings

random_file_name = getattr(settings, 'FILE_UPLOAD_TEMP_DIR', '/tmp')
random_file_name +=  '/' + ''.join([choice('abcdefg') for i in range(12)]) + '.jpg'

destination = open(random_file_name, 'wb+')
for chunk in request.FILES['image'].chunks():
    destination.write(chunk)
destination.close()

Then, you can open it from disk:

image = Image.open(random_file_name)
if image.mode != "RGB":
    image = image.convert("RGB")

...

This URL may help you:

https://docs.djangoproject.com/en/dev/topics/http/file-uploads/

nandoquintana
  • 400
  • 3
  • 14
  • Yes, I had the enctype tag.Your solution would most problably work but it is boring to have to do all this stuff :(. The solution I provided may be a cleaner way to achieve what I wanted to do. Thanks! – gueux Sep 21 '12 at 08:56
1

I finally found a cleaner solution: I removed the "required=True" from my models and defined a clean() method which does the job in my form models:

#Form
class GpsImForm(forms.Form):
    image = forms.ImageField(required=True)
    gps_data = forms.CharField()

    def clean(self):
        super(forms.Form, self)).clean()
        if not self.cleaned_data['gps_data']:  # the user can provide the gps_data manually
            if self.cleaned_data['image']:     # if he provided no gps_data but an image
                i = Image.open(self.cleaned_data['image'])
                ... # functions to extract exif data from i
            else:
                msg = _("You have to provide an image or a gps_data.")
                self._errors['gps_data'] = self.error_class([msg]) 
        return self.cleaned_data


#View
def gpsim_gen_view(request):
    if request.method == 'POST':
        form = GpsImForm(request.POST, request.FILES)
        if form.is_valid():
            obj = form.save()
            return ... #returns the gpsim
    else:
        form = GpsImForm()
    return direct_to_template(request, 'gpsim_generate.html', {'form': form,})
gueux
  • 323
  • 1
  • 12