Django Tastypie 反序列化多部分/表单数据以上传文件
Posted
技术标签:
【中文标题】Django Tastypie 反序列化多部分/表单数据以上传文件【英文标题】:Django Tastypie Deserializing Multipart/Form-Data To Upload File 【发布时间】:2013-04-11 21:11:22 【问题描述】:我正在尝试通过 Multipart/Form-Data 表单和 Tastypie API 上传文件,但遇到了一些问题:
我的模特:
class Client(models.Model):
account = models.ForeignKey(Account)
client_image = models.FileField(upload_to=client_image_path, default="/assets/img/default-user-image.png", blank=True, null=True)
client_image_thumb = models.FileField(upload_to=client_image_thumb_path, default="/assets/img/default-user-image.png", blank=True, null=True)
我正在使用 Tastypie Issue#42 中概述的自定义反序列化方法:
class MultipartResource(object):
def deserialize(self, request, data, format=None):
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
return data
return super(MultipartResource, self).deserialize(request, data, format)
def put_detail(self, request, **kwargs):
if request.META.get('CONTENT_TYPE').startswith('multipart') and \
not hasattr(request, '_body'):
request._body = ''
return super(MultipartResource, self).put_detail(request, **kwargs)
这是我对应的ModelResource:
class ClientResource(MultipartResource, ModelResource):
account = fields.ForeignKey(AccountResource, 'account')
class Meta():
queryset = Client.objects.all()
always_return_data = True
resource_name = 'account/clients/client-info'
authorization = AccountLevelAuthorization()
list_allowed_methods = ['get','post','put','delete','patch']
detail_allowed_methods = ['get', 'post', 'put', 'delete','patch']
authentication = ApiKeyAuthentication()
filtering =
'username': ALL,
如果我使用内容类型 application/JSON 进行 POST 并且不包含 client_image 字段,它将成功创建一个新的客户端对象。这表明模型/资源正在正常工作。
但是,当我尝试使用 Multipart/Form-Data 内容类型时,我可以看到它通过我的反序列化器适当地通过此有效负载:
------WebKitFormBoundaryp0Q7Q9djlsvVGwbb
Content-Disposition: form-data; name="%0D%0A%22account%22"
"/api/v1/account/account-info/21/",
------WebKitFormBoundaryp0Q7Q9djlsvVGwbb
Content-Disposition: form-data; name="client_image"; filename="donavan.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryp0Q7Q9djlsvVGwbb--
我在调试时也看到了这个 QueryDict,它正确显示了 InMemoryUploadedFile:
<QueryDict: u'client_image': [<InMemoryUploadedFile: donavan.jpg (image/jpeg)>], u'%0D%0A%22account%22': [u'"/api/v1/account/account-info/21/"']>
但我不断收到此错误:
error_message: "" traceback: "Traceback (最近一次调用最后一次): 文件 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/resources.py”, 第 202 行,在包装器中 response = callback(request, *args, **kwargs) 文件 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/resources.py”, 第 440 行,在 dispatch_list 中返回 self.dispatch('list', request, **kwargs)文件“/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/resources.py”, 第 472 行,在 dispatch response = method(request, **kwargs) 文件中 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/resources.py”, 第 1328 行,在 post_list updated_bundle = self.obj_create(bundle, **self.remove_api_resource_names(kwargs)) 文件“/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/resources.py”, 第 2104 行,在 obj_create bundle = self.full_hydrate(bundle) 文件中 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/resources.py”, 第 890 行,在 full_hydrate 值 = field_object.hydrate(bundle) 文件中 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/fields.py”, 第 732 行,水合物值 = super(ToOneField, self).hydrate(bundle) 文件 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/tastypie/fields.py”, 第 165 行,在水合物 elif self.attribute 和 getattr(bundle.obj, self.attribute,无):文件 “/Users/stevewirig/Documents/www/vu/venv/lib/python2.7/site-packages/django/db/models/fields/related.py”, 第 343 行,在 get 中提出 self.field.rel.to.DoesNotExist DoesNotExist "
有什么想法可以解决这个问题吗?提前致谢!
【问题讨论】:
【参考方案1】:按如下方式初始化序列化器:
serializer = Serializer(formats=['json'])
【讨论】:
【参考方案2】:当我在未提供必要字段的情况下发布数据时发生这种情况。发布时必须提供那些不能为空的字段。
【讨论】:
以上是关于Django Tastypie 反序列化多部分/表单数据以上传文件的主要内容,如果未能解决你的问题,请参考以下文章
Django/Tastypie - DELETE 请求删除所有内容
Django RESTful API - django-piston 与 django-tastypie