Django - make ModelForm (of an ImageField) accept only certain types of images
django, django-forms, django-models, python, validation
Solution
The `ImageField` validators already verify that the uploaded file is a valid image file supported by Pillow. This is enough to prevent any malicious code injection - the worst that can happen is that someone uploads a file with a different extension than its file format.
I generally don't verify if an uploaded image is indeed the format it portraits to be. As long as it is a valid image file, and the file extension is in my allowed extension, I accept the uploaded file.
You can, however, easily override the `clean_photo` method to determine and verify the actual file type:
from django.utils.image import Image
def clean_photo(self):
photo = self.cleaned_data.get(['photo'])
if photo:
format = Image.open(photo.file).format
photo.file.seek(0)
if format in settings.VALID_IMAGE_FILETYPES:
return photo
raise forms.ValidationError(...)
The `photo.file.seek(0)` part is important, without it you will run into problems when saving the file!!
Note that `format` is not necessarily equal to the content type or the extension: in the case of `.png` it is `'PNG'`, and in the case of `.jpg` it's `'JPEG'`. I don't know if other formats follow suit; you'll have to test that for yourself.
`Image.open` does not load the entire file content, just the header, so this method is quite fast. Using `timeit` and a random `.png` file, I've run the following code 1,000,000 times:
format = Image.open(g.photo).format
g.photo.seek(0)
The average time for this code was 0.0001 seconds, so yeah, lightning fast.
Problem
I am using Pillow 2.3.0 with Django and I have an ImageField in my models.py like so: ``` class UserImages(models.Model): user = models.ForeignKey(User) photo = models.ImageField(upload_to=get_file_path) ``` and I have a form like so: ``` class UploadImageForm(forms.ModelForm): class Meta: model = UserImages fields = ['photo'] ``` How do I make it so that the UploadImageForm only accepts png's and jpeg's? What I tried is adding this clean method to the form: ``` def clean_photo(self): photo = self.cleaned_data.get('photo', False) if photo: fileType = photo.content_type if fileType in settings.VALID_IMAGE_FILETYPES: #png and jpeg return photo raise forms.ValidationError('FileType not supported: only upload jpegs and pngs.') ``` but according to this documentation (https://docs.djangoproject.com/en/1.5/topics/http/file-uploads/#uploadedfile-objects) it says that "You'll still need to validate that the file contains the content that the content-type header claims – 'trust but verify'." How do I verify that the user did infact upload the file type which he claimed to upload?