当前位置: 首页 > 面试题库 >

Django REST Framework上传图片:“提交的数据不是文件”

邢俊悟
2023-03-14
问题内容

正在研究如何在Django中上传文件,在这里我遇到了一个不容易理解的问题,并出现了以下错误:

提交的数据不是文件。检查表单上的编码类型。

下面是详细信息。

注意:我还查看了Django Rest Framework ImageField,并尝试了

serializer = ImageSerializer(data=request.data, files=request.FILES)

但我明白了

TypeError:init()得到了意外的关键字参数“文件”

我有一个Image要通过Django REST框架与之交互的模型:

models.py

class Image(models.Model):
    image = models.ImageField(upload_to='item_images')
    owner = models.ForeignKey(
        User, related_name='uploaded_item_images',
        blank=False,
    )
    time_created = models.DateTimeField(auto_now_add=True)

serializers.py

class ImageSerializer(serializers.ModelSerializer):
    image = serializers.ImageField(
        max_length=None, use_url=True,
    )

    class Meta:
        model = Image
        fields = ("id", 'image', 'owner', 'time_created', )

settings.py

'DEFAULT_PARSER_CLASSES': (
    'rest_framework.parsers.JSONParser',
    'rest_framework.parsers.FormParser',
    'rest_framework.parsers.MultiPartParser',
),

前端(使用AngularJS和angular-restmod或$resource)JSON以owner和image形式发送数据:

输入:

{"owner": 5, "image": "data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0A..."}

在后端,request.data显示

{u'owner': 5, u'image': u'data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0AKgAAA..."}

但随后ImageSerializer(data=request.data).errors显示错误

ReturnDict([('image', [u'The submitted data was not a file. Check the encoding type on the form.'])])

我想知道该如何解决该错误?

编辑:JS部分

相关的前端代码由两部分组成:a angular-file-dnd directive(在此处可用)将文件拖放到页面上,和angular-restmod提供CRUD操作:

<!-- The template: according to angular-file-dnd, -->
<!-- it will store the dropped image into variable $scope.image -->
<div file-dropzone="[image/png, image/jpeg, image/gif]" file="image" class='method' data-max-file-size="3" file-name="imageFileName">
  <div layout='row' layout-align='center'>
    <i class="fa fa-upload" style='font-size:50px;'></i>
  </div>
  <div class='text-large'>Drap & drop your photo here</div>
</div>



# A simple `Image` `model` to perform `POST`
$scope.image_resource = Image.$build();

$scope.upload = function() {
  console.log("uploading");
  $scope.image_resource.image = $scope.image;
  $scope.image_resource.owner = Auth.get_profile().user_id;
  return $scope.image_resource.$save();
};

关于该问题的更新:现在我切换到using ng-file-upload,它以正确的格式发送图像数据。


问题答案:

你遇到的问题是Django REST框架希望通过标准文件上传方法将文件作为多部分表单数据上传。这通常是一个file字段,但是JavaScript Blob对象也适用于AJAX。

你正在寻找使用base64编码的字符串而非原始文件(默认情况下不支持)上传文件。那里有a的Base64ImageField实现,但是最有前途的是pull请求。

由于这些文件主要是为Django REST框架2.x设计的,因此我对pull请求中的一个文件进行了改进,并创建了一个应与DRF 3兼容的文件。

serializers.py

from rest_framework import serializers    

class Base64ImageField(serializers.ImageField):
    """
    A Django REST framework field for handling image-uploads through raw post data.
    It uses base64 for encoding and decoding the contents of the file.

    Heavily based on
    https://github.com/tomchristie/django-rest-framework/pull/1268

    Updated for Django REST framework 3.
    """

    def to_internal_value(self, data):
        from django.core.files.base import ContentFile
        import base64
        import six
        import uuid

        # Check if this is a base64 string
        if isinstance(data, six.string_types):
            # Check if the base64 string is in the "data:" format
            if 'data:' in data and ';base64,' in data:
                # Break out the header from the base64 content
                header, data = data.split(';base64,')

            # Try to decode the file. Return validation error if it fails.
            try:
                decoded_file = base64.b64decode(data)
            except TypeError:
                self.fail('invalid_image')

            # Generate file name:
            file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
            # Get the file name extension:
            file_extension = self.get_file_extension(file_name, decoded_file)

            complete_file_name = "%s.%s" % (file_name, file_extension, )

            data = ContentFile(decoded_file, name=complete_file_name)

        return super(Base64ImageField, self).to_internal_value(data)

    def get_file_extension(self, file_name, decoded_file):
        import imghdr

        extension = imghdr.what(file_name, decoded_file)
        extension = "jpg" if extension == "jpeg" else extension

        return extension

应该用它代替ImageField Django REST框架提供的标准。所以你的序列化器会变成

class ImageSerializer(serializers.ModelSerializer):
    image = Base64ImageField(
        max_length=None, use_url=True,
    )

    class Meta:
        model = Image
        fields = ("id", 'image', 'owner', 'time_created', )

这应该允许你指定base64编码的字符串,或者指定BlobDjango REST框架通常期望的标准对象。



 类似资料:
  • 本文向大家介绍文件上传,iframe跨域数据提交的实现,包括了文件上传,iframe跨域数据提交的实现的使用技巧和注意事项,需要的朋友参考一下 1、文件上传,图片上传,第三方uploadify插件,http://www.uploadify.com/about/ 2、用iframe上传文件,提交表单,主要思路就是:  a、js创建form表单,iframe,添加到body里,form的target要

  • 本文向大家介绍基于ASP.NET+EasyUI框架实现图片上传提交表单功能(js提交图片),包括了基于ASP.NET+EasyUI框架实现图片上传提交表单功能(js提交图片)的使用技巧和注意事项,需要的朋友参考一下 我的风格,先给大家展示下效果图,具体效果图如下所示,如果大家感觉还不错很满意请参考实现代码。 HTML的代码: JS代码: 后台一般处理程序的代码: 上传图片的一般处理程序: 提交表单

  • 本文向大家介绍JavaScript实现图片上传并预览并提交ajax,包括了JavaScript实现图片上传并预览并提交ajax的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了JavaScript实现图片上传并预览并提交ajax的具体代码,供大家参考,具体内容如下 图片上传并预览 HTML css JS 上传图片提交ajax 如果想把图片信息通过ajax传给后端,则需要通过new Fo

  • 上传证件照片。支持 jpeg、jpg、bmp、png 格式,图片大小不超过2M。 // $path string 图片路径 $response = $app->media->upload($path);

  • 问题内容: 在我的Web应用程序中,我有一个图像上传模块。我想检查上传的文件是图像文件还是其他文件。我在服务器端使用Java。 图像在Java中读取,然后将其写入磁盘 我应该如何检查,究竟是图像还是其他? 任何建议或链接将不胜感激。 问题答案: 我假设您正在servlet上下文中运行它。如果仅根据文件扩展名检查内容类型是可以承受的,则可使用来获取mime类型(内容类型)。只需检查它是否以开头。 默

  • 问题内容: 我意识到这个问题的变体已经出现了很多次,但是我找不到在这种情况下能回答这个问题的人。 我正在使用第三方fileuploader,该文件利用jQuery并在文件上传完成时给出成功回调。 我要实现的是一个带有文本字段的表单以及fileuploader,当您单击“提交”时,该表单将触发上传功能(文件开始使用进度条开始上传),并等待成功回调之前继续提交表格。 我必须立即承认我是jQuery的白