'ImageFieldFile' object has no attribute 'content_type' only after picture has already been uploaded then isn't either changed or removed

GetItDone picture GetItDone · Oct 8, 2012 · Viewed 8.3k times · Source

I'm working on a project that uses both django registration and django profiles. I have a form that allows users edit/create a profile, which includes uploading a photo. Everything works fine in the following situations: a profile is created or edited and no image has ever been uploaded; a profile is edited/created and an image is uploaded; once an image is uploaded, the profile can be edited as long as the image that was previously uploaded is either changed or removed... The place I run into issues is if there is an existing profile image, and the user tries to edit his/her profile without making any changes to the current image (i.e. removing or replacing it). In that situation, I get the error 'ImageFieldFile' object has no attribute 'content_type'. Any ideas as to why this is happening. I have tried variations of other answers found in stack overflow, but couldn't get any of them to work as they were stated. What I currently have is a variation of one of those with changes I made:

class UserProfileForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(UserProfileForm, self).__init__(*args, **kwargs)
        try:
            self.fields['email'].initial = self.instance.user.email
        except User.DoesNotExist:
            pass

    email = forms.EmailField(label="Primary email", help_text='')

    class Meta:
        model = UserAccountProfile
            exclude = ('user', 'broadcaster', 'type')
            widgets = {
            ...
        }


    def save(self, *args, **kwargs):
        u = self.instance.user
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile

    def clean_avatar(self):
        avatar = self.cleaned_data['avatar']            

        if avatar:
            w, h = get_image_dimensions(avatar)
            max_width = max_height = 500
            if w >= max_width or h >= max_height:
                raise forms.ValidationError(u'Please use an image that is %s x %s pixels or less.' % (max_width, max_height))

            main, sub = avatar.content_type.split('/')
            if not (main == 'image' and sub in ['jpeg', 'pjpeg', 'gif', 'png']):
                raise forms.ValidationError(u'Please use a JPEG, GIF or PNG image.')

            if len(avatar) > (50 * 1024):
                raise forms.ValidationError(u'Avatar file size may not exceed 50k.')

        else:
            pass

        return avatar

Thanks for any help or advice.

Here is the full traceback:

Traceback:
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "C:\Python27\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
  20.                 return view_func(request, *args, **kwargs)
File "C:\Python27\lib\site-packages\profiles\views.py" in edit_profile
  197.         if form.is_valid():
File "C:\Python27\lib\site-packages\django\forms\forms.py" in is_valid
  124.         return self.is_bound and not bool(self.errors)
File "C:\Python27\lib\site-packages\django\forms\forms.py" in _get_errors
  115.             self.full_clean()
File "C:\Python27\lib\site-packages\django\forms\forms.py" in full_clean
  270.         self._clean_fields()
File "C:\Python27\lib\site-packages\django\forms\forms.py" in _clean_fields
  290.                     value = getattr(self, 'clean_%s' % name)()
File "C:\Documents and Settings\user\projects\xlftv\lftv\userprofiles\forms.py" in clean_avatar
  146.          main, sub = avatar.content_type.split('/')

Exception Type: AttributeError at /instructor_profiles/edit
Exception Value: 'ImageFieldFile' object has no attribute 'content_type'

Answer

Termi picture Termi · Apr 18, 2017

When a file is uploaded, based on the file size it will be an instance of InMemoryUploadedFile class or a TemporaryUploadedFile class which are subclasses of UploadedFile class.

And image model fields are saved as django.db.models.fields.files.ImageFieldFile objects.

So when the form is submitted again without modifying the image field, that field will be an instance of django.db.models.fields.files.ImageFieldFile rather the uploaded file django.core.files.uploadedfile.UploadedFile instance. So check for the type of the form field before accessing the content_type attribute.

from django.core.files.uploadedfile import UploadedFile
from django.db.models.fields.files import ImageFieldFile

def clean_avatar(self):
    avatar = self.cleaned_data['avatar']            

    if avatar and isinstance(avatar, UploadedFile):
        w, h = get_image_dimensions(avatar)
        max_width = max_height = 500
        if w >= max_width or h >= max_height:
            raise forms.ValidationError(u'Please use an image that is %s x %s pixels or less.' % (max_width, max_height))

        main, sub = avatar.content_type.split('/')
        if not (main == 'image' and sub in ['jpeg', 'pjpeg', 'gif', 'png']):
            raise forms.ValidationError(u'Please use a JPEG, GIF or PNG image.')

        if len(avatar) > (50 * 1024):
            raise forms.ValidationError(u'Avatar file size may not exceed 50k.')

    elif avatar and isinstance(avatar, ImageFieldFile):
        # something
        pass

    else:
        pass

    return avatar