somesh
somesh

Reputation: 548

django backend doesn't support absolute paths

I am working Crop Images in a Django Application

using this tutorial Crop Images in Django

Myform:

class UploadImageForm(forms.ModelForm):
x = forms.FloatField(widget=forms.HiddenInput())
y = forms.FloatField(widget=forms.HiddenInput())
width = forms.FloatField(widget=forms.HiddenInput())
height = forms.FloatField(widget=forms.HiddenInput())
primaryphoto = forms.ImageField(required=False,
                                error_messages={'invalid': _("Image files only")}, widget=forms.FileInput)
class Meta:
    model = User
    fields = ['primaryphoto', 'x', 'y', 'width', 'height',]


def save(self):
    user = super(UploadImageForm, self).save()
    x = self.cleaned_data.get('x')
    y = self.cleaned_data.get('y')
    w = self.cleaned_data.get('width')
    h = self.cleaned_data.get('height')

    image = Image.open(user.primaryphoto)
    cropped_image = image.crop((x, y, w + x, h + y))
    resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
    resized_image.save(user.primaryphoto.path)

    return user

myview:

def upload_image(request):
if request.method == 'POST':
    form = UploadImageForm(request.POST, request.FILES, instance=request.user)
    if form.is_valid():
        form.save()
        return redirect('/profile')
else:
    form = UploadImageForm(instance=request.user)
return render(request, 'student/uploadimageform.html', {'form': form})

storage_backend.py:

from storages.backends.s3boto3 import S3Boto3Storage

class MediaStorage(S3Boto3Storage):
    location = 'media'
    file_overwrite = False

However, when I uploaded it to run on AWS, I got the error message that the backend does not support absolute paths (in reference to primaryphoto.path in the form where the photo is cropped). I was wondering what I have to change to get it working with S3. I've found some resources that say change primaryphoto.path to primaryphoto.name, but that hasn't worked for me. I was wondering if you had any recommendations to solve this problem?

Here Image is uploaded to S3 Bucket but issue is throwing above error. Please help me anyone. Thanks in advance ...

Edit answer:

    def save(self):
    user = super(UploadImageForm, self).save()
    x = self.cleaned_data.get('x')
    y = self.cleaned_data.get('y')
    w = self.cleaned_data.get('width')
    h = self.cleaned_data.get('height')
    try:
        image = Image.open(user.primaryphoto)
        cropped_image = image.crop((x, y, w + x, h + y))
        resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)
        resized_image.save(user.primaryphoto.path)
    except:
        pass

    return user

Here issue is throwing error but image is uploading locally and S3 bucket properly ... for handling path error i am using try, except block

Upvotes: 5

Views: 15084

Answers (4)

Takib Ahmed
Takib Ahmed

Reputation: 41

For me default.storage.write() did not work, image.save() did not work, this one worked. See this code if anyone is still interested. I apologize for the indentation. My project was using Cloudinary and Django small project.

from io import BytesIO
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage as storage    

def save(self, *args, **kargs):
super(User, self).save(*args, **kargs)
# After save, read the file
image_read = storage.open(self.profile_image.name, "r")
image = Image.open(image_read)
    if image.height > 200 or image.width > 200:
       size = 200, 200
    
      # Create a buffer to hold the bytes
       imageBuffer = BytesIO()

      # Resize  
       image.thumbnail(size, Image.ANTIALIAS)

      # Save the image as jpeg to the buffer
       image.save(imageBuffer, image.format)

      # Check whether it is resized
       image.show()

      # Save the modified image
       user = User.objects.get(pk=self.pk)
       user.profile_image.save(self.profile_image.name, ContentFile(imageBuffer.getvalue()))

       image_read = storage.open(user.profile_image.name, "r")
       image = Image.open(image_read)
       image.show()

    image_read.close()

Upvotes: 2

24thDan
24thDan

Reputation: 123

For those redirected here from google, here's code tested and working on aws based on answers from @Alexandar Dimitro and other comments on this page.

  from django.core.files.storage import default_storage as storage

  def save(self):
        user = super(UploadImageForm, self).save()
        x = self.cleaned_data.get('x')
        y = self.cleaned_data.get('y')
        w = self.cleaned_data.get('width')
        h = self.cleaned_data.get('height')

        image = Image.open(user.primaryphoto)
        cropped_image = image.crop((x, y, w + x, h + y))
        resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)

        fh = storage.open(user.primaryphoto.name, "wb")
        picture_format = 'png'
        resized_image.save(fh, picture_format)
        fh.close()        
        return user

Upvotes: 1

Alexandar Dimitrov
Alexandar Dimitrov

Reputation: 11

This one worked for me. Just replace the save() method in your form.

from django.core.files.storage import default_storage as storage

      def save(self):
            user = super(UploadImageForm, self).save()
            x = self.cleaned_data.get('x')
            y = self.cleaned_data.get('y')
            w = self.cleaned_data.get('width')
            h = self.cleaned_data.get('height')

            image = Image.open(user.primaryphoto)
            cropped_image = image.crop((x, y, w + x, h + y))
            resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)

            fh = storage.open(user.primaryphoto.name, "w")
            picture_format = 'png'
            resized_image.save(fh, picture_format)
            fh.close()        
            resized_image.save(user.primaryphoto.path)
            return user

Upvotes: 1

Lemayzeur
Lemayzeur

Reputation: 8525

Try the following instead.

I don't test it, but some explanations will be good: We convert the image into string buffer in order to create a Django InMemoryUploadedFile with the cropped image. In this case, we don't use path. Try it and let me know you face any other errors.

import os
from io import BytesIO as StringIO # python3
from django.core.files.uploadedfile import InMemoryUploadedFile

def save(self):
    user = super(UploadImageForm, self).save()
    x = self.cleaned_data.get('x')
    y = self.cleaned_data.get('y')
    w = self.cleaned_data.get('width')
    h = self.cleaned_data.get('height')

    image = Image.open(user.primaryphoto)
    cropped_image = image.crop((x, y, w + x, h + y))
    resized_image = cropped_image.resize((200, 200), Image.ANTIALIAS)

    filename = os.path.splitext(resized_image.name)[0] 

    output = StringIO()
    resized_image.save(output, format='JPEG', quality=95)
    output.seek(0) #Change the stream position to the given byte offset.


    new_image = InMemoryUploadedFile(output,'ImageField',\
        "%s.jpg" % filename , 'image/jpeg', output.__sizeof__(), None)

    user.primaryphoto = new_image
    user.save()

    return user

Upvotes: 1

Related Questions