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

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

问题描述

我正在倾斜如何在Django上传文件,这里我遇到一个应该是平凡的问题,错误:


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


以下是详细信息。






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

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

但我得到


TypeError: __ init __()得到一个意想不到的关键字参数'files'







我有一个图像,我想通过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 数据与所有者 image 的形式:



输入:



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

在后端, request.data 显示

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

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

  ReturnDict [('image',[u'提交的数据不是文件。检查表单上的编码类型'])])

我想知道我应该做什么来修复错误?






编辑:JS部分



相关的前端代码由两部分组成:一个 angular-file-dnd 指令 here )可将该文件放在页面上,并且 angular-restmod ,它提供CRUD操作:

 <! - 模板:根据angular-file-dnd, - > 
<! - 它会将丢弃的图像存储到变量$ scope.image - >
< div file-dropzone =[image / png,image / jpeg,image / gif]file =imageclass ='method'data-max-file-size =3 = 映像文件名称 >
< div layout ='row'layout-align ='center'>
< i class =fa fa-uploadstyle ='font-size:50px;'>< / i>
< / div>
< div class ='text-large'> Drap&把你的照片放在这里< / div>
< / div>



#一个简单的`Image``模型来执行`POST`
$ scope.image_resource = Image。$ build();

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









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

解决方案

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



您正在使用base64编码的字符串而不是原始文件上传文件,。有 Base64ImageField 在那里的实现,但最有希望一个来自拉请求



由于这些主要是为Django REST框架2.x设计的,所以我已经从pull请求中改进了一个,并创建了一个与DRF 3兼容的应用程序。



< h1> serializers.py

  from rest_framework import serializers 

class Base64ImageField(serializers.ImageField):

通过原始帖子数据处理图像上传的Django REST框架字段
它使用base64对文件的内容进行编码和解码

重新基于
https://github.com/tomchristie/django-rest-framework/pull/1268

为Django REST框架更新3.


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

#检查这是否是base64字符串
if isinstance(data,six.string_types):
#检查base64字符串是否为data:格式
如果数据中的data:和; base64中的数据:
#从base64内容中分出标题
header,data = data.split('; base64,')

#尝试解码文件。如果失败返回验证错误。
try:
decoded_file = base64.b64decode(data)
除了TypeError:
self.fail('invalid_image')

#生成文件名:
file_name = str(uuid.uuid4())[:12]#12个字符是足够的。
#获取文件扩展名:
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)

返回超级(Base64ImageField,self).to_internal_value(data)

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

extension = imghdr.what(file_name,decoding_file)
extension =jpgif extension ==jpegelse extension

返回扩展

这应该用于替换标准的所以你的序列化器将成为

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


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

这应该允许你指定一个base64编码的字符串, code> Blob Django REST框架通常需要的对象。


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.

Below is the detail.


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

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

but I get

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


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

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',
),

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

Input:

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

In the backend, request.data shows

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

But then ImageSerializer(data=request.data).errors shows the error

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?


EDIT: JS part

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



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

解决方案

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.

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.

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.

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

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', )

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

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

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