Django Rest Framework Angulars 使用 ModelSerializer 上传文件

Django Rest Framework Angulars upload file using ModelSerializer

我正在尝试使用 Django Rest Framework 和 AngularJs 上传图像 我正在使用 ng-file-upload 上传带有 AngularJs.

的图像

我看到可以使用 ApiViewSet 来执行此操作。但是由于我的图像在模型中并且我使用 ModelSerializer 所以如果可能的话我更喜欢使用 ModelViewSet。

问题是当我上传图片时出现错误:

image: ["The submitted data was not a file. Check the encoding type on the form."]

这是我的代码

Models.py

class Image(models.Model):
   image = models.ImageField(upload_to="articles")
   article = models.ForeignKey(Article)

Serializers.py

class ImageSerializer(serializers.ModelSerializer):
   class Meta:
       #article = ArticleSerializer(read_only=True, required=False)
       image = serializers.ImageField(use_url=True, allow_empty_file=True)
       model = Image

       fields = ('id', 'image', 'article')
       read_only_fields = ('id', )

#def get_validation_exclusions(self, *args, **kwargs):
#    exclusions = super(ImageSerializer, self).get_validation_exclusion()

#   return exclusions + ['article']

Views.py

class ImageViewSet(viewsets.ModelViewSet):
queryset = Image.objects.order_by('id')
serializer_class = ImageSerializer

class ImageArticleViewset(viewsets.ModelViewSet):
    queryset = Image.objects.select_related('article').all()
    serializer_class = ImageSerializer

    def list(self, request, *args, image_pk=None):
       queryset = self.queryset.filter(article__id=image_pk)
       serializer = self.serializer_class(queryset, many=True)

       return Response(serializer.data)

和控制器

(function () {

'use strict';

angular
    .module(nameProject + '.article.post.controller')
    .controller('ArticlePostController', ArticlePostController);

ArticlePostController.$inject = ["$scope", "Articles", "Upload", "$timeout"];

function ArticlePostController($scope, Articles, Upload, $timeout) {
    var vm = this;
    vm.postArticle = postArticle;


    $scope.$watch('files', function () {

        $scope.upload($scope.files);
        console.debug("files = ", $scope.files);
        //console.debug("upload = ", $scope.upload);

    });

    $scope.upload = function (files) {
        if (files && files.length) {
            for (var i = 0; i < files.length; i++) {
                var file = files[i];
                console.debug("file = ", file, "type = ", file.type);

                Upload.upload({
                    url: '/api/v1/images/',
                    fields: {
                        'idArticle': 1,
                        'article': 1,
                        'image': file
                    },
                    file: file,
                    image:file
                }).progress(function (evt) {
                    var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                    $scope.log = 'progress: ' + progressPercentage + '% ' +
                    evt.config.file.name + '\n' + $scope.log
                }).success(function (data, status, headers, config) {
                    $timeout(function () {

                        console.log("data === ", data.result);

                        $scope.log = 'file: ' + config.file.name + ', Response: ' + JSON.stringify(data) + '\n' + $scope.log;


                    });
                });
            }
        }
    };




}
})();

还有这一行

console.debug("files = ", $scope.files);

在控制台打印

type =  image/jpeg

Jade 模板

form.form-signin(ng-submit="vm.postArticle()" enctype="multipart/form-data")
h2.form-signin-heading Post un article
    input.input-block-level(type="text", name="title", placeholder="Title" ng-model="vm.title")
    input.input-block-level(type="number", name="price", placeholder="Price" ng-model="vm.price")
    input.input-block-level(type="text", name="content", placeholder="Description" ng-model="vm.description")
    input.input-block-level(type="number", name="quantity", placeholder="Quantity" ng-model="vm.quantity")
    input.input-block-level(type="text", name="color", placeholder="Color" ng-model="vm.color")
    input.input-block-level(type="text", name="state", placeholder="State" ng-model="vm.state")
    input.input-block-level(type="number", name="year", placeholder="Year" ng-model="vm.year")
    p watching model
    div(class="button" ngf-select ng-model="files" ngf-multiple="multiple") Select File on file change:
    button.btn.btn-large.btn-primary(type="submit") Submit article

Django 的 REST Framework 默认处理上传文件的方式是检查文件头并决定如何处理它:

http://www.django-rest-framework.org/api-guide/parsers/#fileuploadparser

默认情况下,ng-file-upload 以 json 格式上传文件,这意味着您上传的文件作为 Base64 提交给 Django,Django 将尝试使用以下:

http://www.django-rest-framework.org/api-guide/parsers/#fileuploadparser

这不适用于默认的 Django 文件字段,有多种方法可以完成此操作,一种是在您的请求中使用以下选项 (sendFieldAs):

Upload.upload({
    url: '/api/v1/images/',
    ...
    sendFieldsAs: form,

这将以表单形式提交数据,Django REST 框架将对其进行处理。其他选项包括解码 Base64 和手动创建要与文件字段一起使用的文件,与 sendFieldAs 选项相比会增加开销。