问题是Content-Type
您的请求标头中的设置不正确。[参考]
Tastypie 仅识别xml
、json
和。因此,在发送 POST 请求时,您需要将请求标头设置为其中之一(例如,)。yaml
bplist
Content-Type
application/json
编辑:
您似乎正在尝试通过 Tastypie 发送包含文件的多部分表单。
Issac Kelly 为路线图 1.0 最终版(尚未发布)提供 Tastypie 文件上传支持的一点背景:
- 实现一个 Base64FileField,它接受用于 PUT/POST 的 base64 编码文件(如问题 #42 中的文件),并为 GET 请求提供 URL。这将是主要的 sweetpie repo 的一部分。
- 我们希望鼓励其他实现作为独立项目来实现。有几种方法可以做到这一点,其中大多数都有些挑剔,并且它们都有不同的缺点,我们希望有其他选择,并记录每种方法的优缺点
这意味着至少目前,Tastypie 还没有正式支持分段文件上传。但是,野外有一些叉子据说运行良好,这就是其中之一。不过我还没有测试过。
现在让我尝试解释您遇到该错误的原因。
在 Tastypieresource.py
中,第 452 行:
def dispatch(self, request_type, request, **kwargs):
"""
Handles the common operations (allowed HTTP method, authentication,
throttling, method lookup) surrounding most CRUD interactions.
"""
allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None)
if 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META:
request.method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE']
request_method = self.method_check(request, allowed=allowed_methods)
method = getattr(self, "%s_%s" % (request_method, request_type), None)
if method is None:
raise ImmediateHttpResponse(response=http.HttpNotImplemented())
self.is_authenticated(request)
self.is_authorized(request)
self.throttle_check(request)
# All clear. Process the request.
request = convert_post_to_put(request)
response = method(request, **kwargs)
# Add the throttled request.
self.log_throttled_access(request)
# If what comes back isn't a ``HttpResponse``, assume that the
# request was accepted and that some action occurred. This also
# prevents Django from freaking out.
if not isinstance(response, HttpResponse):
return http.HttpNoContent()
return response
convert_post_to_put(request)
从这里调用。这是代码
convert_post_to_put
:
# Based off of ``piston.utils.coerce_put_post``. Similarly BSD-licensed.
# And no, the irony is not lost on me.
def convert_post_to_VERB(request, verb):
"""
Force Django to process the VERB.
"""
if request.method == verb:
if hasattr(request, '_post'):
del(request._post)
del(request._files)
try:
request.method = "POST"
request._load_post_and_files()
request.method = verb
except AttributeError:
request.META['REQUEST_METHOD'] = 'POST'
request._load_post_and_files()
request.META['REQUEST_METHOD'] = verb
setattr(request, verb, request.POST)
return request
def convert_post_to_put(request):
return convert_post_to_VERB(request, verb='PUT')
而且此方法并不是真正打算处理多部分,因为它具有阻止任何进一步访问的副作用,request.body
因为
_load_post_and_files()
方法会将_read_started
标志设置为True
:
姜戈request.body
和_load_post_and_files()
:
@property
def body(self):
if not hasattr(self, '_body'):
if self._read_started:
raise Exception("You cannot access body after reading from request's data stream")
try:
self._body = self.read()
except IOError as e:
six.reraise(UnreadablePostError, UnreadablePostError(*e.args), sys.exc_info()[2])
self._stream = BytesIO(self._body)
return self._body
def read(self, *args, **kwargs):
self._read_started = True
return self._stream.read(*args, **kwargs)
def _load_post_and_files(self):
# Populates self._post and self._files
if self.method != 'POST':
self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
return
if self._read_started and not hasattr(self, '_body'):
self._mark_post_parse_error()
return
if self.META.get('CONTENT_TYPE', '').startswith('multipart'):
if hasattr(self, '_body'):
# Use already read data
data = BytesIO(self._body)
else:
data = self
try:
self._post, self._files = self.parse_file_upload(self.META, data)
except:
# An error occured while parsing POST data. Since when
# formatting the error the request handler might access
# self.POST, set self._post and self._file to prevent
# attempts to parse POST data again.
# Mark that an error occured. This allows self.__repr__ to
# be explicit about it instead of simply representing an
# empty POST
self._mark_post_parse_error()
raise
else:
self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()
因此,您可以(尽管可能不应该)
通过调用
convert_post_to_VERB()
设置猴子补丁 Tastypie 的方法,然后立即设置,以便
读取并且不会设置
:request._body
request.body
_read_started=False
_load_post_and_files()
_body
_read_started=True
def convert_post_to_VERB(request, verb):
"""
Force Django to process the VERB.
"""
if request.method == verb:
if hasattr(request, '_post'):
del(request._post)
del(request._files)
request.body # now request._body is set
request._read_started = False # so it won't cause side effects
try:
request.method = "POST"
request._load_post_and_files()
request.method = verb
except AttributeError:
request.META['REQUEST_METHOD'] = 'POST'
request._load_post_and_files()
request.META['REQUEST_METHOD'] = verb
setattr(request, verb, request.POST)
return request