Объект' ImageFieldFile 'не имеет атрибута' content type ' только после того, как картинка уже загружена, а затем не изменяется и не удаляется


Я работаю над проектом, который использует как регистрацию django, так и профили django. У меня есть форма, которая позволяет пользователям редактировать / создавать профиль, который включает в себя загрузку фотографии. Все прекрасно работает в следующих ситуациях: профиль создается или редактируется, и ни одно изображение никогда не загружалось; профиль редактируется/создается, и изображение загружается; после загрузки изображения профиль можно редактировать, пока изображение, которое было загружено ранее, либо изменено, либо удалено... То место, где я сталкиваюсь с проблемами, - это если есть существующее изображение профиля, и пользователь пытается отредактировать свой профиль, не внося никаких изменений в текущее изображение (т. е. удаляя или заменяя его). В этой ситуации я получаю ошибку 'ImageFieldFile' объект не имеет атрибута 'content_type'. Любые идеи относительно того, почему это происходит. Я пробовал варианты других ответов, найденных в Stack overflow, но не смог заставить ни один из них работать так, как они были заявлены. То, что у меня в настоящее время есть, является вариацией одного из те, с изменениями, которые я сделал:

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

Спасибо за любую помощь или совет.

Вот полный traceback:

Traceback:
File "C:Python27libsite-packagesdjangocorehandlersbase.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "C:Python27libsite-packagesdjangocontribauthdecorators.py" in _wrapped_view
  20.                 return view_func(request, *args, **kwargs)
File "C:Python27libsite-packagesprofilesviews.py" in edit_profile
  197.         if form.is_valid():
File "C:Python27libsite-packagesdjangoformsforms.py" in is_valid
  124.         return self.is_bound and not bool(self.errors)
File "C:Python27libsite-packagesdjangoformsforms.py" in _get_errors
  115.             self.full_clean()
File "C:Python27libsite-packagesdjangoformsforms.py" in full_clean
  270.         self._clean_fields()
File "C:Python27libsite-packagesdjangoformsforms.py" in _clean_fields
  290.                     value = getattr(self, 'clean_%s' % name)()
File "C:Documents and Settingsuserprojectsxlftvlftvuserprofilesforms.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'
2 2

2 ответа:

Итак, если вы посмотрите на последнюю точку в вашей обратной трассировке, вы увидите, что ваша ошибка исходит из этой строки main, sub = avatar.content_type.split('/'), которая, по-видимому, из вашего метода clean_avatar. Похоже, вы пытаетесь убедиться, что это изображение... Я должен представить, что есть другой способ сделать это.

Похоже на худший вариант, вы должны быть в состоянии разобрать avatar.name, чтобы проверить расширения файлов (см. https://docs.djangoproject.com/en/dev/ref/files/file/#django.core.files.File )

Кстати, способ получить content_type для пример - ContentType.get_for_model(avatar).

При загрузке файла, в зависимости от размера файла, это будет экземпляр класса InMemoryUploadedFile или класса TemporaryUploadedFile, которые являются подклассами класса UploadedFile.

Поля

И модели изображений сохраняются в виде объектов django.db.models.fields.files.ImageFieldFile.

Таким образом, когда форма будет отправлена снова без изменения поля изображения, это поле будет экземпляром django.db.models.fields.files.ImageFieldFile, а не загруженным файлом django.core.files.uploadedfile.UploadedFile. Поэтому проверьте тип поля формы, прежде чем обращаться к атрибуту content_type.
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