UnicodeDecodeError:“UTF-8”编解码器无法解码位置 0 中的字节 0xff:起始字节无效。 DRF

问题描述 投票:0回答:1

django 上有一个后端,还有一个 postgres 数据库,用于存储有关项目的数据,包括图片。从数据库获取图片存在问题,我已经看过足够多的解决方案,但没有一个有效。

序列化器.py

import base64
import uuid
import imghdr

class Base64ImageField(serializers.ImageField):
    def to_internal_value(self, data):
        if isinstance(data, str) and 'data:' in data and ';base64,' in data:
            header, data = data.split(';base64,')
            try:
                decoded_file = base64.b64decode(data)
            except (TypeError, ValueError):
                self.fail('invalid_image')
            file_name = str(uuid.uuid4())[:12] 
            file_extension = self.get_file_extension(file_name, decoded_file)
            complete_file_name = f"{file_name}.{file_extension}"
            data = ContentFile(decoded_file, name=complete_file_name)

        return super(Base64ImageField, self).to_internal_value(data)

    def get_file_extension(self, file_name, decoded_file):
        extension = imghdr.what(file_name, decoded_file)
        return extension or 'jpg'

class CreateItemSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    photo = Base64ImageField(required=True)
    class Meta:
        model = CreateItem
        fields = '__all__'


    def create(self, validated_data):
        items = CreateItem.object.create_item(
            name = validated_data.get('name'),
            price = validated_data.get('price'),
            description = validated_data.get('description'),
            type_item = validated_data.get('type_item'),
            photo=validated_data.get('photo')
        )
        return items

views.py


class GetItemView(APIView):
    serializer_class = CreateItemSerializer
    def get(self, request):
        items = CreateItem.object.all()  
        response_data = {
            'items': [
                {   
                    'photo': item.photo,
                    'name': item.name,
                    'description': item.description,
                    'type_item': item.type_item,
                    'price': item.price,
                }
                for item in items
            ]
        }
        return Response(response_data, status=status.HTTP_200_OK)

完整的错误追溯

Internal Server Error: /api/v1/item/items-get/
Traceback (most recent call last):
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response
    response = response.render()
               ^^^^^^^^^^^^^^^^^
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/django/template/response.py", line 114, in render
    self.content = self.rendered_content
                   ^^^^^^^^^^^^^^^^^^^^^
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/rest_framework/response.py", line 74, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/rest_framework/renderers.py", line 100, in render
    ret = json.dumps(
          ^^^^^^^^^^^
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/rest_framework/utils/json.py", line 25, in dumps
    return json.dumps(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
          ^^^^^^^^^^^
  File "/usr/lib/python3.12/json/encoder.py", line 200, in encode
    chunks = self.iterencode(o, _one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/json/encoder.py", line 258, in iterencode
    return _iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
  File "/home/anton/Documents/e-m/e-market/backend/my_backend/venv_em/lib/python3.12/site-packages/rest_framework/utils/encoders.py", line 52, in default
    return obj.decode()
           ^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
[04/Oct/2024 18:59:30] "GET /api/v1/item/items-get/ HTTP/1.1" 500 115134

也许问题出在desirealizer上,但如果是这样,我不知道如何解决它。

python django serialization django-rest-framework utf-8
1个回答
0
投票

您遇到的错误是由于序列化器和视图中处理图像数据的方式造成的。问题是,当您尝试序列化响应的图像字段时,它会尝试将二进制图像数据解码为 UTF-8 文本,这是不正确的。让我们修改您的代码以正确处理这个问题

序列化器.py

from rest_framework import serializers
from django.core.files.base import ContentFile
import base64
import uuid
import imghdr

class Base64ImageField(serializers.ImageField):
    def to_internal_value(self, data):
        if isinstance(data, str) and 'data:' in data and ';base64,' in data:
            header, data = data.split(';base64,')
            try:
                decoded_file = base64.b64decode(data)
            except (TypeError, ValueError):
                self.fail('invalid_image')
            file_name = str(uuid.uuid4())[:12] 
            file_extension = self.get_file_extension(file_name, decoded_file)
            complete_file_name = f"{file_name}.{file_extension}"
            data = ContentFile(decoded_file, name=complete_file_name)

        return super(Base64ImageField, self).to_internal_value(data)

    def get_file_extension(self, file_name, decoded_file):
        extension = imghdr.what(file_name, decoded_file)
        return extension or 'jpg'

    def to_representation(self, value):
        if not value:
            return None
        return value.url  # Return the URL of the image instead of the file object

class CreateItemSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    photo = Base64ImageField(required=True)
    
    class Meta:
        model = CreateItem
        fields = '__all__'

    def create(self, validated_data):
        return CreateItem.objects.create(**validated_data)


views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import CreateItem
from .serializers import CreateItemSerializer

class GetItemView(APIView):
    def get(self, request):
        items = CreateItem.objects.all()
        serializer = CreateItemSerializer(items, many=True)
        return Response({'items': serializer.data}, status=status.HTTP_200_OK)
© www.soinside.com 2019 - 2024. All rights reserved.