Django 1.3 是可以接受的。所以我可以用 request.raw_post_data 或 request.read() 做一些事情(或者其他更好的访问方法)。有任何想法吗?
您不想触摸request.raw_post_data
- 这意味着将整个请求正文读入内存,如果您正在谈论文件上传,这可能是一个非常大的数量,所以request.read()
要走的路。您也可以使用 Django <= 1.2 执行此操作,但这意味着要深入研究HttpRequest
以找出使用私有接口的正确方法,然后确保您的代码也与 Django >= 1.3 兼容是一个真正的麻烦.
我建议您要做的是复制该类的现有文件上传行为部分MultiPartParser
:
- 从中检索上传处理
request.upload_handlers
程序(默认情况下为MemoryFileUploadHandler
& TemporaryFileUploadHandler
)
- 确定请求的内容长度(在
HttpRequest
或中搜索 Content-LengthMultiPartParser
以查看执行此操作的正确方法。)
- 确定上传文件的文件名,方法是让客户端使用 url 的最后一个路径部分指定它,或者让客户端在
Content-Disposition
header的 "filename=" 部分指定它。
- 对于每个处理程序,
handler.new_file
使用相关参数调用(模拟字段名称)
request.read()
使用和调用handler.receive_data_chunk()
每个块读取请求正文。
- 对于每个处理程序调用
handler.file_complete()
,如果它返回一个值,那就是上传的文件。
如何推断正在发送的 mime 类型?如果我没看错的话,PUT 主体就是没有前奏的文件。因此,我是否要求用户在其标题中指定 mime 类型?
要么让客户端在 Content-Type 标头中指定它,要么使用python 的 mimetype 模块来猜测媒体类型。
我很想知道你是如何处理这件事的——这是我一直想审视自己的事情,如果你能发表评论让我知道进展如何,那就太好了!
Ninefingers根据要求进行编辑,这就是我所做的,完全基于上述内容和 django 源。
upload_handlers = request.upload_handlers
content_type = str(request.META.get('CONTENT_TYPE', ""))
content_length = int(request.META.get('CONTENT_LENGTH', 0))
if content_type == "":
return HttpResponse(status=400)
if content_length == 0:
# both returned 0
return HttpResponse(status=400)
content_type = content_type.split(";")[0].strip()
try:
charset = content_type.split(";")[1].strip()
except IndexError:
charset = ""
# we can get the file name via the path, we don't actually
file_name = path.split("/")[-1:][0]
field_name = file_name
因为我在这里定义了 API,所以跨浏览器支持不是问题。就我的协议而言,不提供正确的信息是一个错误的请求。对于是否要说image/jpeg; charset=binary
或是否要允许不存在的字符集,我有两种看法。无论如何,我将Content-Type
有效地设置为客户端责任。
同样,对于我的协议,文件名是传入的。我不确定field_name
参数是什么,来源也没有给出太多线索。
下面发生的事情实际上比看起来要简单得多。您询问每个处理程序是否会处理原始输入。正如上述状态的作者,你有MemoryFileUploadHandler
&TemporaryFileUploadHandler
默认情况下。好吧,事实证明,MemoryFileUploadHandler
当被要求创建一个new_file
决定是否处理文件时(基于各种设置)。如果它决定要这样做,它会抛出一个异常,否则它不会创建文件并让另一个处理程序接管。
我不确定它的目的counters
是什么,但我从源头上保留了它。其余的应该是直截了当的。
counters = [0]*len(upload_handlers)
for handler in upload_handlers:
result = handler.handle_raw_input("",request.META,content_length,"","")
for handler in upload_handlers:
try:
handler.new_file(field_name, file_name,
content_type, content_length, charset)
except StopFutureHandlers:
break
for i, handler in enumerate(upload_handlers):
while True:
chunk = request.read(handler.chunk_size)
if chunk:
handler.receive_data_chunk(chunk, counters[i])
counters[i] += len(chunk)
else:
# no chunk
break
for i, handler in enumerate(upload_handlers):
file_obj = handler.file_complete(counters[i])
if not file_obj:
# some indication this didn't work?
return HttpResponse(status=500)
else:
# handle file obj!