'ImageFieldFile'对象仅在图片上传后才有属性'content_type',然后才更改或删除

时间:2012-10-08 16:15:07

标签: django django-forms django-models django-profiles

我正在开发一个同时使用django注册和django个人资料的项目。我有一个表单,允许用户编辑/创建个人资料,其中包括上传照片。在以下情况下一切正常:创建或编辑配置文件,并且没有上传任何图像;编辑/创建配置文件并上传图像;上传图像后,只要先前上传的图像被更改或删除,就可以编辑个人资料...我遇到问题的地方是,如果有现有的个人资料图像,并且用户试图编辑他的/她的个人资料,不对当前图像进行任何更改(即删除或替换它)。在那种情况下,我得到错误'ImageFieldFile'对象没有属性'content_type'。关于为什么会发生这种情况的任何想法。我已经尝试过在堆栈溢出中找到的其他答案的变体,但是无法让它们中的任何一个按照它们的说明工作。我目前所拥有的是我做出的改变之一的变体:

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:
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'

2 个答案:

答案 0 :(得分:3)

上传文件时,根据文件大小,它将是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

答案 1 :(得分:0)

因此,如果您查看追溯中的最后一点,您会发现错误来自此行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)