<blockquote>
<p>Django 1.3 is acceptable. So I can
either do something with
request.raw_post_data or
request.read() (or alternatively some
other better method of access). Any
ideas?</p>
</blockquote>
<p>你不想触碰<code>request.raw_post_data</code>-这意味着将整个请求体读入内存,如果你在讨论文件上传可能会有很大的量,所以<code>request.read()</code>才是正确的方法。在Django<;=1.2的情况下也可以这样做,但这意味着在<code>HttpRequest</code>中寻找正确的方法来使用私有接口,这是一个真正的阻力,可以确保代码也与Django>;=1.3兼容。</p>
<p>我建议您要做的是复制<a href="http://code.djangoproject.com/browser/django/trunk/django/http/multipartparser.py#L184" rel="noreferrer">existing file upload behaviour parts of the ^{<cd4>} class</a>:</p>
<ol>
<li>从<code>request.upload_handlers</code>(默认为<code>MemoryFileUploadHandler</code>&;<code>TemporaryFileUploadHandler</code>)检索上载句柄</li>
<li>确定请求的内容长度(在<code>HttpRequest</code>或<code>MultiPartParser</code>中搜索内容长度以查看正确的方法。)</li>
<li>通过让客户端使用url的最后一个路径部分指定文件名,或者让客户端在“filename=”part of <a href="http://www.ietf.org/rfc/rfc2183.txt" rel="noreferrer">the ^{<cd10>} header</a>中指定文件名,来确定上载文件的文件名。</li>
<li>对于每个处理程序,使用相关参数调用<code>handler.new_file</code>(模拟字段名)</li>
<li>使用<code>request.read()</code>并为每个块调用<code>handler.receive_data_chunk()</code>以块形式读取请求正文。</li>
<li>对于每个处理程序调用<code>handler.file_complete()</code>,如果它返回一个值,那就是上传的文件。</li>
</ol>
<blockquote>
<p>How can I deduce the mime type of what
is being sent? If I've got it right, a
PUT body is simply the file without
prelude. Do I therefore require that
the user specify the mime type in
their headers?</p>
</blockquote>
<p>要么让客户端在内容类型头中指定它,要么使用<a href="http://docs.python.org/library/mimetypes.html" rel="noreferrer">python's mimetype module</a>猜测媒体类型。</p>
<p>我很想知道你是怎么处理这件事的-这是我一直想调查自己的事情,如果你能评论让我知道它是怎么回事就好了!</p>
<hr/>
<p><strong>由Ninefingers编辑</strong>根据要求,这是我所做的,完全基于上述内容和django来源。</p>
<pre><code>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
</code></pre>
<p>既然我在这里定义了API,跨浏览器支持就不再是问题了。就我的协议而言,不提供正确的信息是一个坏请求。我对是否要说<code>image/jpeg; charset=binary</code>或是否允许不存在的字符集有两种看法。无论如何,我把设置<code>Content-Type</code>有效地作为客户端的责任。</p>
<p>类似地,对于我的协议,文件名被传入。我不确定<code>field_name</code>参数的用途,而且源代码没有给出太多线索。</p>
<p>下面发生的事情实际上比看起来简单得多。询问每个处理程序是否将处理原始输入。作为上述状态的作者,默认情况下您拥有<code>MemoryFileUploadHandler</code>&;<code>TemporaryFileUploadHandler</code>。好吧,当被要求创建一个<code>new_file</code>时<code>MemoryFileUploadHandler</code>将决定它是否处理该文件(基于各种设置)。如果它决定要这样做,它会抛出一个异常,否则它不会创建文件并让另一个处理程序接管。</p>
<p>我不知道<code>counters</code>的目的是什么,但我一直不知道它的来源。其余的应该是直截了当的。</p>
<pre><code>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!
</code></pre>