Search code examples
djangodjango-modelsimagefielddjango-uploads

ValueError on ImageField when trying to delete image or creating new user in Django


I have put an ImageField on my Django model, and with the pre-existent profiles it works (the image upload), but I can't delete the image from the admin panel and I can't create a new user.
The thrown error is:

ValueError at /admin/custom_user/customuser/1/
The 'avatar' attribute has no file associated with it.
Request Method: POST
Request URL: http://localhost:8000/admin/custom_user/customuser/1/
Django Version: 1.8
Exception Type: ValueError
Exception Value: The 'avatar' attribute has no file associated with it.
Exception Location: /home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/db/models/fields/files.py in _require_file, line 46
Python Executable: /home/stefano/projects/blog-project/blogprojectenv/bin/python
Python Version: 2.7.6
Python Path:
['/home/stefano/projects/blog-project',
'/home/stefano/projects/blog-project/blogprojectenv/lib/python2.7',
'/home/stefano/projects/blog-project/blogprojectenv/lib/python2.7/plat-x86_64-linux-gnu',
'/home/stefano/projects/blog-project/blogprojectenv/lib/python2.7/lib-tk',
'/home/stefano/projects/blog-project/blogprojectenv/lib/python2.7/lib-old',
'/home/stefano/projects/blog-project/blogprojectenv/lib/python2.7/lib-dynload',
'/usr/lib/python2.7',
'/usr/lib/python2.7/plat-x86_64-linux-gnu',
'/usr/lib/python2.7/lib-tk',
'/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages'] Server time: Thu, 24 Mar 2016 13:12:38 +0000

This is the model

class CustomUser(AbstractBaseUser, PermissionsMixin):
    first_name   = models.CharField(max_length=254, blank=True)
    second_name  = models.CharField(max_length=254, blank=True)
    email        = models.EmailField(blank=True, unique=True)
    date_joined  = models.DateTimeField(_('date joined'), default=datetime.now())
    avatar       = models.ImageField('profile picture', upload_to='images/avatars/', null=True, blank=True)
    is_active    = models.BooleanField(default=True)
    is_admin     = models.BooleanField(default=False)
    is_staff     = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'second_name']

    objects = CustomUserManager()

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

    def save(self, *args, **kwargs):
        pil_image_obj = Image.open(self.avatar)
        new_image = resizeimage.resize_width(pil_image_obj, 300)

        new_image_io = BytesIO()
        new_image.save(new_image_io, format='JPEG')

        temp_name = self.avatar.name
        self.avatar.delete(save=False)

        self.avatar.save(
            temp_name,
            content=ContentFile(new_image_io.getvalue()),
            save=False
        )

        super(CustomUser, self).save(*args, **kwargs)

I've tried to put null=True and blank=True on the model, but the error is still there. I've tried to put required=False on "init" method in forms.py

class CustomUserChangeForm(forms.ModelForm):
    email = forms.EmailField(label='', required=True, widget = forms.TextInput(
        attrs = {
            'placeholder': 'E-Mail',
            'class': 'form-control'
        }
    ))

    first_name = forms.CharField(label='', required=True, widget=forms.TextInput(
        attrs = {
            'placeholder': 'First name',
            'class': 'form-control'
        }
    ))

    second_name = forms.CharField(label='', required=True, widget=forms.TextInput(
        attrs = {
            'placeholder': 'Second name',
            'class': 'form-control'
        }
    ))

    avatar = forms.ImageField(label='', required=False, widget=forms.FileInput(
        attrs = {
            'class': 'form-control',
            'label': 'Profile pic'
        }
    ))

    class Meta:
        model = CustomUser
        fields = ('email', 'first_name', 'second_name', 'avatar')

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(CustomUserChangeForm, self).__init__(*args, **kwargs)
        self.fields['avatar'].required = False

    def clean_email_address(self):
        email = self.cleaned_data.get('email')
        if self.user and self.user.email == email:
            return email
        if CustomUser.objects.filter(email=email).count():
            raise forms.ValidationError(u'That email address already exists.')
        return email

    def save(self, commit=True):
        user = super(CustomUserChangeForm, self).save(commit=False)
        user.email = self.cleaned_data['email']

        if commit:
            user.save()

        return user

Still there.

What can be done?

EDIT: Here's the complete traceback

Environment:


Request Method: POST
Request URL: http://localhost:8000/admin/custom_user/customuser/1/

Django Version: 1.8
Python Version: 2.7.6
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'blog',
 'custom_user',
 'django_markdown',
 'parsley')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware')


Traceback:
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper
  616.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  110.                     response = view_func(request, *args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  57.         response = view_func(request, *args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner
  233.             return view(request, *args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in change_view
  1519.         return self.changeform_view(request, object_id, form_url, extra_context)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
  34.             return bound_func(*args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  110.                     response = view_func(request, *args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
  30.                 return func.__get__(self, type(self))(*args2, **kwargs2)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/utils/decorators.py" in inner
  145.                     return func(*args, **kwargs)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in changeform_view
  1467.                 self.save_model(request, new_object, form, not add)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in save_model
  1078.         obj.save()
File "/home/stefano/projects/blog-project/custom_user/models.py" in save
  66.       pil_image_obj = Image.open(self.avatar)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/PIL/Image.py" in open
  2261.         fp.seek(0)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/core/files/utils.py" in <lambda>
  20.     seek = property(lambda self: self.file.seek)
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/db/models/fields/files.py" in _get_file
  49.         self._require_file()
File "/home/stefano/projects/blog-project/blogprojectenv/local/lib/python2.7/site-packages/django/db/models/fields/files.py" in _require_file
  46.             raise ValueError("The '%s' attribute has no file associated with it." % self.field.name)

Exception Type: ValueError at /admin/custom_user/customuser/1/
Exception Value: The 'avatar' attribute has no file associated with it.

Solution

  • I think that a condition asking if self.avatar before opening the avatar image could work because if there is not an avatar there is not reason to delete it, from my point of view. Something like this:

    def save(self, *args, **kwargs):
        if self.avatar:
            pil_image_obj = Image.open(self.avatar)
            new_image = resizeimage.resize_width(pil_image_obj, 300)
    
            new_image_io = BytesIO()
            new_image.save(new_image_io, format='JPEG')
    
            temp_name = self.avatar.name
            self.avatar.delete(save=False)
    
            self.avatar.save(
                temp_name,
                content=ContentFile(new_image_io.getvalue()),
                save=False
            )
    
        super(CustomUser, self).save(*args, **kwargs)
    

    I hope this can help you to find the solution. Thanks :)