Django restframework не может получить почтовые данные с помощью парсера нескольких частей

я пытаюсь сохранить объект с изображением с помощью django restframework, но когда я использую классы FormParser и MultiPartParser, объект request.data получает вроде бы закодированные сообщения, а когда я пытаюсь декодировать с помощью utf-8, он выдает ошибку, говоря, что эти данные не utf-8

я хочу иметь доступ к данным request.data и иметь возможность сохранить изображение для будущих запросов

вот моя функция просмотра:

@parser_classes([FormParser, MultiPartParser])
@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def products(request):
    if request.method == 'POST':
        print(request.data)

        serializer = ProductSerializer(data=request.data)
        
        serializer.initial_data['user'] = request.user.pk

        serializer.initial_data['price'] = float(
            request.data['price'])

        serializer.initial_data['quantity'] = int(
            request.data['quantity'])

        if serializer.is_valid():
            serializer.save()
            return Response({'message': "product added"}, status=status.HTTP_201_CREATED)
        else:
            print(serializer.errors)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

мой код переднего плана:

export const addProduct = async (product) => {
    const fd = new FormData();
    fd.append("name", product.name);
    fd.append("price", product.price);
    fd.append("quantity", product.quantity);
    fd.append("image_url", product.image_url);

    console.log(product.image_url) //this prints a file object

    const response = await fetch(`${URL}/products`, {
        method: "POST",
        headers: {
            "Content-Type": `multipart/form-data; boundary=${fd._boundary}`,
        },
        body: fd,
    })
    return response
}

Данные изображения не кодируются как UTF-8 (возможно! и если это так), вы можете использовать поле FileField или ImageField в вашем сериализаторе, вместе с классами FormParser и MultiPartParser!

[UPDATED] Ваше представление должно быть таким:

@parser_classes([FormParser, MultiPartParser])
@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def products(request):
    if request.method == 'POST':
        serializer = ProductSerializer(data=request.data)
        serializer.initial_data['user'] = request.user.pk

        if 'price' in request.data:
            serializer.initial_data['price'] = float(request.data['price'])
        else:
            return Response({'error': 'price not found in request data'}, status=status.HTTP_400_BAD_REQUEST)

        if 'quantity' in request.data:
            serializer.initial_data['quantity'] = int(request.data['quantity'])
        else:
            return Response({'error': 'quantity not found in request data'}, status=status.HTTP_400_BAD_REQUEST)

        if serializer.is_valid():
            serializer.save()
            return Response({'message': "product added"}, status=status.HTTP_201_CREATED)
        else:
            print(serializer.errors)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

И сериализатор:

class ProductSerializer(serializers.ModelSerializer):
    image_url = serializers.ImageField()
    
    class Meta:
        model = Product
        fields = ['name', 'price', 'quantity', 'image_url', 'user']

Итак, когда я удалил заголовки, все работает нормально, так что, очевидно, если вы решили использовать multipart/form-data, граница не должна появляться в данных файла, которые в конечном итоге получает сервер.

Проблема с multipart/form-data заключается в том, что разделитель границ не должен присутствовать в данных файла (см. RFC 2388; раздел 5.2 также включает довольно неубедительное оправдание отсутствия надлежащего совокупного MIME-типа, который позволяет избежать этой проблемы).

поэтому я исправил это, удалив границу во фронтенде, в результате чего мой код фронтенда выглядит примерно так

const fd = new FormData();
fd.append("name", product.name);
fd.append("price", product.price);
fd.append("quantity", product.quantity);
fd.append("image_url", product.image_url);

console.log(product.image_url) // this print a File object

const response = await fetch(`${URL}/products`, {
    method: "POST",
    headers: {
        Authorization: `token ${localStorage.getItem("auth")}`
    },
    body: fd,
})
Вернуться на верх