【问题标题】:Django Rest Framework Angulars upload file using ModelSerializerDjango Rest Framework Angulars 使用 ModelSerializer 上传文件
【发布时间】:2015-10-06 02:03:00
【问题描述】:

我正在尝试使用 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."]

这是我的代码

模型.py

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

序列化器.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

翡翠模板

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

【问题讨论】:

    标签: python angularjs django rest upload


    【解决方案1】:

    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 File 字段,有不同的方法可以实现这一点,一种是在您的请求中使用以下选项 (sendFieldAs):

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

    这会将数据作为表单提交,Django REST 框架将按应有的方式处理该数据。其他选项包括解码 Base64 并手动创建要与文件字段一起使用的文件,与 sendFieldAs 选项相比,这会增加开销。

    【讨论】:

    • 我尝试了第一个解决方案sendFieldsAs: "form" 我得到了image: ["No file was submitted."] 我将使用 FileUploadParser
    猜你喜欢
    • 2015-12-08
    • 2017-03-21
    • 2021-02-06
    • 2021-05-11
    • 1970-01-01
    • 2014-09-21
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多