Загрузка файла через Angular (с использованием FormData) в django-rest-framework
Я перерыл все возможные вопросы на StackOverflow и сообщения в блогах, и все еще сталкиваюсь с проблемами.
 Я пытаюсь загрузить файл в конечную точку django-rest-framework с помощью Angular 12.
Это код фронтенда:
uploadCameraImage(id: CameraInterface["id"], image: File): Observable<CameraInterface> {
  const formData: FormData = new FormData();
  formData.append("image", image);
  const httpOptions = {
    headers: new HttpHeaders({
      "Content-Type": "multipart/form-data",
      "Content-Disposition": `attachment; filename=${image.name}`
    })
  };
  return this.http.put<CameraInterface>(`${this.configUrl}/camera/${id}/image/`, formData, httpOptions);
}
 Вот соответствующие django-rest-framework части:
# This is the main base serializer used for other operations
class EquipmentItemSerializer(serializers.Serializer):
    class Meta:
        fields = [
            'created_by',
            'created',
            'updated',
            'brand',
            'name',
            'image',
        ]
        read_only_fields = ['image']
        abstract = True
# This is the base serializer only used for the image upload
class EquipmentItemImageSerializer(serializers.Serializer):
    class Meta:
        fields = ['image']
        abstract = True
# This is the main serializer used for all other operations (create/delete...)
class CameraSerializer(EquipmentItemSerializer, serializers.ModelSerializer):
    class Meta:
        model = Camera
        fields = '__all__'
# This is the serializer used for the image upload in the @action below
class CameraImageSerializer(EquipmentItemImageSerializer, serializers.ModelSerializer):
    class Meta:
        model = Camera
        fields = EquipmentItemImageSerializer.Meta.fields
# This is the base view set
class EquipmentItemViewSet(viewsets.ModelViewSet):
    renderer_classes = [BrowsableAPIRenderer, CamelCaseJSONRenderer]
    permission_classes = [IsEquipmentModeratorOrReadOnly]
    http_method_names = ['get', 'post', 'head', 'put', 'patch']
    def get_queryset(self):
        q = self.request.GET.get('q')
        manager = self.get_serializer().Meta.model.objects
        return manager.all()
    def image_upload(self, request, pk):
        obj = self.get_object()
        serializer = self.serializer_class(obj, data=request.data, partial=True)
        # NOTE: I have to do this because FileUploadParser hardcodes 'file' while my model has 'image' :(
        serializer.initial_data['image'] = serializer.initial_data['file']
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, HTTP_400_BAD_REQUEST)
    class Meta:
        abstract = True
# This the main view set
class CameraViewSet(EquipmentItemViewSet):
    serializer_class = CameraSerializer
    @action(
        detail=True,
        methods=['PUT'],
        # NOTE THE DIFFERENT SERIALIZER FOR THE ACTION
        serializer_class=CameraImageSerializer,
        # I'VE TRIED ALL COMBINATIONS OF PARSERS INCLUIDING FormParser AND MultiPartParser
        parser_classes=[FileUploadParser],
    )
    def image(self, request, pk):
        return super(CameraViewSet, self).image_upload(request, pk)
 При использовании этого кода результирующее сообщение об ошибке заключается в том, что загружаемый файл не является допустимым изображением. Я отладил код, и он сводится к проверке Django с помощью ImageField, используя PIL для открытия изображения.
 Я полагаю, что файл, сохраненный как Django TemporaryFile, - это не только PNG, который я отправляю, но и все тело моего PUT запроса. Вот начало:
-----------------------------127295088417990690601368813565
Content-Disposition: form-data; name="image"; filename="9f1971c6-b8e6-4c5a-bd55-958b7fdd6ab1.png"
Content-Type: image/png
PNG
(binary data follows)
Если я добавлю FormParser в парсер моих image @action, я все равно получу такое же поведение. Если я также добавлю MultiPartParser, я получу пустые request.data и request.files.
Может кто-нибудь помочь?