Загрузка файла через 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
.
Может кто-нибудь помочь?