Python Django REST框架上载图像:“0”;提交的数据不是一个文件;
我正在学习如何用Django上传文件,在这里我遇到了一个应该是很小的问题,错误如下: 提交的数据不是文件。检查表单上的编码类型 以下是细节Python Django REST框架上载图像:“0”;提交的数据不是一个文件;,python,angularjs,django,django-rest-framework,Python,Angularjs,Django,Django Rest Framework,我正在学习如何用Django上传文件,在这里我遇到了一个应该是很小的问题,错误如下: 提交的数据不是文件。检查表单上的编码类型 以下是细节 注意:我也看了,我试了一下 serializer = ImageSerializer(data=request.data, files=request.FILES) 但我明白了 TypeError:\uuuu init\uuuu()获取了意外的关键字参数“files” 我有一个图像模型,我想通过Django REST框架与之交互: models.py
注意:我也看了,我试了一下
serializer = ImageSerializer(data=request.data, files=request.FILES)
但我明白了
TypeError:\uuuu init\uuuu()
获取了意外的关键字参数“files”
我有一个
图像
模型,我想通过Django REST框架与之交互:
models.py
序列化程序.py
设置.py
前端(使用AngularJS和AngularRestMod或$resource
)发送JSON
数据和所有者
和图像
,格式如下:
输入:
在后端,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部分 相关的前端代码由两部分组成:一个
角度文件dnd
指令
(可用)将文件放到页面上,另一个角度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();
};
把你的照片拖放到这里
#一个简单的“Image”模型来执行“POST”`
$scope.image_resource=image.$build();
$scope.upload=函数(){
控制台日志(“上传”);
$scope.image_resource.image=$scope.image;
$scope.image\u resource.owner=Auth.get\u profile().user\u id;
返回$scope.image_资源。$save();
};
关于这个问题的更新:现在我切换到使用
ng file upload
,它以正确的格式发送图像数据。您遇到的问题是Django REST框架,通过标准的文件上传方法。这是,但对于AJAX来说是最重要的
您希望使用base64编码的字符串来上载文件,而不是使用原始文件。a的实现有很多种,但最有希望的一种
由于这些主要是为Django REST framework 2.x设计的,因此我改进了pull请求中的一个,并创建了一个应该与DRF 3兼容的框架
序列化程序.py
这应该用于替代Django REST框架提供的标准ImageField
。所以您的序列化程序将成为
class ImageSerializer(serializers.ModelSerializer):
image = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = Image
fields = ("id", 'image', 'owner', 'time_created', )
这应该允许您指定base64编码的字符串,或者Django REST框架通常期望的标准
Blob
对象。我几天前遇到了同样的问题。这是我的django rest框架视图,用于处理文件上载
views.py
在前端,我使用lib
这是我的文件输入
<div ng-file-drop="" ng-file-select="" ng-model="organizer.photo" class="drop-box" drag-over-class="{accept:'dragover', reject:'dragover-err', delay:100}" ng-multiple="false" allow-dir="true" accept="image/*">
Drop Images or PDFs<div>here</div>
</div>
你能更新你的代码以包含你用来发布数据的表单和任何相关的js吗?@JamieCounsell:我已经添加了上面的代码。但是我没有使用
标记。@Lelouch:“image”:“data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0A…”
这是哪种文件格式???@Lelouch你能和我分享这方面的最终解决方案吗谢谢!目前,我尝试了一些图像,但得到了一个有效的上传图像。您上载的文件不是图像或图像已损坏。。也许是前端的问题,我会尝试其他前端处理。但我想知道是否有一个地方可以在线测试base64编码字符串是否有效?太棒了,它现在可以工作了!上载的文件现在位于所需的目录中。非常感谢。另一个版本现在似乎出现在PyPI上:在post请求上效果很好,但在put请求上,只有“原始内容”被保存。我尝试使用base64编码字段添加您的工作解决方案,我得到以下输出:异常值:不正确的填充异常位置:/home/bgarcial/.virtualenvs/fuupbol2/lib/python3.5/base64.py在b64decode中,第88行//请参阅更多详细信息,以防原始问题是使用base64编码的图像字符串而不是基于浏览器的文件对象上载文件。不过,当您需要使用标准的Blob
对象异步上载文件时,这可能适用于一般情况。@levi:谢谢!您的angular file upload
解决方案可能更灵活,我应该在将来试用。目前我想我将实现@KevinBrown的解决方案。当你编写file\u form=FileUploadForm(request.POST,request.FILES)
时,FileUploadForm
来自哪里?你能提供更多关于FileUploadForm()
的信息吗
ReturnDict([('image', [u'The submitted data was not a file. Check the encoding type on the form.'])])
<!-- 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();
};
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
class ImageSerializer(serializers.ModelSerializer):
image = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = Image
fields = ("id", 'image', 'owner', 'time_created', )
class PhotoUploadView(APIView):
parser_classes = (FileUploadParser,)
def post(self, request):
user = self.request.user
if not user:
return Response(status=status.HTTP_403_FORBIDDEN)
profile = None
data = None
photo = None
file_form = FileUploadForm(request.POST,request.FILES)
if file_form.is_valid():
photo = request.FILES['file']
else:
return Response(ajax_response(file_form),status=status.HTTP_406_NOT_ACCEPTABLE)
try:
profile = Organizer.objects.get(user=user)
profile.photo = photo
profile.save()
data = OrganizersSerializer(profile).data
except Organizer.DoesNotExist:
profile = Student.objects.get(user=user)
profile.photo = photo
profile.save()
data = StudentsSerializer(profile).data
return Response(data)
<div ng-file-drop="" ng-file-select="" ng-model="organizer.photo" class="drop-box" drag-over-class="{accept:'dragover', reject:'dragover-err', delay:100}" ng-multiple="false" allow-dir="true" accept="image/*">
Drop Images or PDFs<div>here</div>
</div>
(function () {
'use strict';
angular
.module('trulii.utils.services')
.factory('UploadFile', UploadFile);
UploadFile.$inject = ['$cookies', '$http','$upload','$window','Authentication'];
/**
* @namespace Authentication
* @returns {Factory}
*/
function UploadFile($cookies, $http,$upload,$window,Authentication) {
/**
* @name UploadFile
* @desc The Factory to be returned
*/
var UploadFile = {
upload_file: upload_file,
};
return UploadFile;
function upload_file(file) {
return $upload.upload({
url: '/api/users/upload/photo/', // upload.php script, node.js route, or servlet url
//method: 'POST' or 'PUT',
//headers: {'Authorization': 'xxx'}, // only for html5
//withCredentials: true,
file: file, // single file or a list of files. list is only for html5
//fileName: 'doc.jpg' or ['1.jpg', '2.jpg', ...] // to modify the name of the file(s)
//fileFormDataName: myFile, // file formData name ('Content-Disposition'), server side request form name
// could be a list of names for multiple files (html5). Default is 'file'
//formDataAppender: function(formData, key, val){} // customize how data is added to the formData.
// See #40#issuecomment-28612000 for sample code
})
}
}
})();