Django的REST框架上传图片:"所提交的数据是不是一个文件" [英] Django REST Framework upload image: "The submitted data was not a file"
问题描述
我靠在如何上传文件在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 code>显示
{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屋!