Django的REST框架上传图片:"所提交的数据是不是一个文件" [英] Django REST Framework upload image: "The submitted data was not a file"

查看:2539
本文介绍了Django的REST框架上传图片:"所提交的数据是不是一个文件"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我靠在如何上传文件在Django,在这里,我遇到一个应该待琐碎的问题,与错误:

I am leaning how to upload file in Django, and here I encounter a should-be-trivial problem, with the error:

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

The submitted data was not a file. Check the encoding type on the form.

下面是详细信息。

注意:我也看了一下的Django的REST框架的ImageField ,我试图

Note: I also looked at Django Rest Framework ImageField, and I tried

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

但我得到

类型错误: __ __的init()得到了一个意外的关键字参数'文件'

TypeError: __init__() got an unexpected keyword argument 'files'

我有一个图片模式,我想通过Django的REST框架与互动:


I have a Image model which I would like to interact with via Django REST framework:

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和角restmod $资源)发送使用JSON 数据所有者图片的形式是:

The front end (using AngularJS and angular-restmod or $resource) send JSON data with owner and image of the form:

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

在后端, request.data 显示

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

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

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

我不知道我应该做什么来解决这个错误吗?

I wonder what I should do to fix the error?

编辑:JS部分

在相关的前端 codeS由两部分组成:一个角文件DND 指令(可 rel=\"nofollow\">)将文件拖放到页面上,角restmod ,它提供了CRUD操作:

The related front end codes consists of two parts: a angular-file-dnd directive (available here) to drop the file onto the page and angular-restmod, which provides CRUD operations:

<!-- 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();
};



有关的更新问题:现在我转向使用 NG-文件上传,它发送的正确格式的图像数据



An update concerning the problem: right now I switched to using ng-file-upload, which sends image data in proper format.

推荐答案

这是你打的问题是,Django的REST框架的希望文件被上传为多部分表单数据,通过标准的文件上传方法。这是<一个href=\"https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications#Using_hidden_file_input_elements_using_the_click()_method\">typically一个文件字段,但<一个href=\"https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications#Example.3A_Uploading_a_user-selected_file\">JavaScript 的Blob 对象也适用以AJAX。

The problem that you are hitting is that Django REST framework expects files to be uploaded as multipart form data, through the standard file upload methods. This is typically a file field, but the JavaScript Blob object also works for AJAX.

您正在寻找使用base64连接codeD串上传,而不是原始的文件,该文件的默认情况下不支持。有一个 Base64ImageField 的实现在那里,但最有前途的走过来拉申请

You are looking to upload the files using a base64 encoded string, instead of the raw file, which is not supported by default. There are implementations of a Base64ImageField out there, but the most promising one came by a pull request.

由于这些大多设计为Django的REST框架2.x中,我已经在从拉入请求一个完善和创建一个应与DRF 3兼容。

Since these were mostly designed for Django REST framework 2.x, I've improved upon the one from the pull request and created one that should be compatible with DRF 3.

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

这应该代之以Django的REST框架所提供的标准的ImageField 的使用。所以,你的序列化将成为

This should be used in replacement of the standard ImageField provided by Django REST framework. So your serializer would become

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

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

这应该让您无论是指定一个base64-CN codeD字符串或标准的Blob 对象,Django的REST框架通常预期。

This should allow you to either specify a base64-encoded string, or the standard Blob object that Django REST framework typically expects.

这篇关于Django的REST框架上传图片:&QUOT;所提交的数据是不是一个文件&QUOT;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆