简体   繁体   中英

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!

Images are going to contain data which is not safe to represent in UTF-8. If you need to transport image data this way, you should encode it into something else first which is safe in UTF-8, such as base64.

To do this in your Python sender, you can use something like base64.b64encode(img)

And to decode it again on the other side, you will need to use base64.b64decode(img)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM