mandrakeが言うように、HttpResponseのコンストラクターは反復可能なオブジェクトを受け入れます。
幸い、ZIP形式では、アーカイブをシングルパスで作成でき、中央ディレクトリレコードはファイルの最後にあります。

(ウィキペディアからの写真)
そして幸いなことに、zipfile
ファイルを追加するだけである限り、実際にはシークは実行されません。
これが私が思いついたコードです。いくつかのメモ:
- このコードを使用して、大量のJPEG画像を圧縮しています。それらを圧縮する意味はありません。私はZIPをコンテナとしてのみ使用しています。
- メモリ使用量はO(size_of_archive)ではなくO(size_of_largest_file)です。そして、これは私にとっては十分です:潜在的に巨大なアーカイブに追加される多くの比較的小さなファイル
- このコードはContent-Lengthヘッダーを設定しないため、ユーザーは進行状況を適切に示すことができません。すべてのファイルのサイズがわかっている場合は、これを事前に計算できるはずです。
- このようにユーザーに直接ZIPを提供することは、ダウンロードの再開が機能しないことを意味します。
だから、ここに行きます:
import zipfile
class ZipBuffer(object):
""" A file-like object for zipfile.ZipFile to write into. """
def __init__(self):
self.data = []
self.pos = 0
def write(self, data):
self.data.append(data)
self.pos += len(data)
def tell(self):
# zipfile calls this so we need it
return self.pos
def flush(self):
# zipfile calls this so we need it
pass
def get_and_clear(self):
result = self.data
self.data = []
return result
def generate_zipped_stream():
sink = ZipBuffer()
archive = zipfile.ZipFile(sink, "w")
for filename in ["file1.txt", "file2.txt"]:
archive.writestr(filename, "contents of file here")
for chunk in sink.get_and_clear():
yield chunk
archive.close()
# close() generates some more data, so we yield that too
for chunk in sink.get_and_clear():
yield chunk
def my_django_view(request):
response = HttpResponse(generate_zipped_stream(), mimetype="application/zip")
response['Content-Disposition'] = 'attachment; filename=archive.zip'
return response