Search code examples
pythondjangoimagedjango-modelsimagefield

Uploading Image in Django: 'utf-8' codec can't decode byte 0x89 in position 246: invalid start byte


I'm trying to upload images in my api using pure json, but when i tried to upload image in request.Files and the token in request.body, I face this error:

UnicodeDecodeError at /api/auth/set-profile-image/
'utf-8' codec can't decode byte 0x89 in position 246: invalid start byte

and it says:

Unicode error hint
The string that could not be encoded/decoded was: " �PNG

but i'm sending JPG! :D

View.py

@csrf_exempt
def set_profile_image(request):
    if request.method == 'POST':
        request_info = json.loads(request.body)
        token = request_info.get('token')
        img = request.FILES['image']
        if token is not None and img is not None:
            user = User.objects.filter(token=token)
            if user.exists():
                user = user.get()
                form = UploadImage(request.POST, request.FILES['image'])
                if form.is_valid():
                    user.profile_image = form.cleaned_data['image']
                    user.save()
                    response = {
                        'status_code': 200,
                        'image_set': True,
                        'image_url': user.profile_image.url
                    }

Form.py

from django import forms

class UploadImage(forms.Form):
    image = forms.ImageField()

and my test code is:

import requests

data = {
    'token': 'helloworld1--_aFsV-ZVG9lVpi0KSydrx3pG3TSMPqqHVKWD2Yc8bE'
}

url = 'http://localhost:8000/api/auth/set-profile-image/'

with open('test.jpg', 'rb') as img:

    response = requests.post(
        url=url,
        data=data,
        files={
            'image': img
        }
    )

    # print(response.text)
    f = open('test.html', 'wb')
    f.write(response.content)
    f.close()

I'm using ImageField as my db field in models.py

Warmest Regards, Poor Maintenance guy who's stuck in others code!


Solution

  • Ok after some tests and thanks to Jacob See's answer, i found a solution:

    First I encode my image to base64 and sent it through the API like this:

    with open('test.jpg', 'rb') as img:
        data = {
            "token": "some token"
        }
    
        response = requests.post(
            url=url,
            data={
                'data': json.dumps(data),
                'image': b64encode(img.read())
            }
        )
    

    And in my API i do this:

    new_base64_img = request.POST.get('image', None)
    
    try:
        image = Image.open(BytesIO(b64decode(new_base64_img)))
        image_content = ContentFile(b64decode(new_base64_img))
        file_name = "some file name" + image.format
    
        user.profile_image.save(file_name, image_content, save=True)
        return JsonResponse({"OK"})
    
    except IOError:
        return JsonResponse({"Image should be base64 encoded!"})
    

    Problem Solved :D