Djangoでダウンロードするファイルを生成する


96

zipアーカイブを作成してダウンロードすることはできますが、ファイルをハードドライブに保存することはできませんか?

回答:


111

ダウンロードをトリガーするには、Content-Dispositionヘッダーを設定する必要があります。

from django.http import HttpResponse
from wsgiref.util import FileWrapper

# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response

ディスク上のファイルが不要な場合は、使用する必要があります StringIO

import cStringIO as StringIO

myfile = StringIO.StringIO()
while not_finished:
    # generate chunk
    myfile.write(chunk)

オプションでContent-Lengthヘッダーも設定できます:

response['Content-Length'] = myfile.tell()

1
Content-LengthはDjangoミドルウェアで自動的に発生する可能性があると思います
andrewrk

4
この例を使用すると、常に空のファイルがダウンロードされます。
camelCase 2013年

3
@ eleaz28が言ったように、私の場合も空のファイルを作成していました。を取り外したところFileWrapper、うまくいきました。
セバスチャンデプレ

この回答はDjango 1.9では機能しません。次を参照してください:stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
ファイルを読み取りモードで開くと、file.getvalue()で属性エラーが発生します。TextIOWrapperに属性getValueがありません。
Shubham Srivastava

26

一時ファイルを作成した方が幸せです。これは多くのメモリを節約します。1人または2人以上のユーザーが同時にいる場合、メモリの節約が非常に重要であることがわかります。

ただし、StringIOオブジェクトに書き込むことはできます。

>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778

「バッファ」オブジェクトは、778バイトのZIPアーカイブを持つファイルのようなものです。


2
メモリの節約についての良い点。しかし、一時ファイルを使用している場合、それを削除するコードをどこに配置しますか?
アンドリューク

@ superjoe30:定期的なクリーンアップジョブ。Djangoにはすでに古いコマンドを削除するために定期的に実行する必要がある管理コマンドがあります。
S.Lott

@ superjoe30これは/ tmpの
意味

@ S.Lott mod x-sendfileを使用して、作成したファイル(例ではz)を提供することは可能ですか?
2016年

10

代わりにtarファイルを作成しませんか?そのようです:

def downloadLogs(req, dir):
    response = HttpResponse(content_type='application/x-gzip')
    response['Content-Disposition'] = 'attachment; filename=download.tar.gz'
    tarred = tarfile.open(fileobj=response, mode='w:gz')
    tarred.add(dir)
    tarred.close()

    return response

1
Djangoの新しいバージョンでは、content_type=代わりにmimetype=
Guillaume Lebreton 2018年

9

はい。zipfileモジュールzlibモジュール、またはその他の圧縮モジュールを使用して、メモリ内にzipアーカイブを作成できます。HttpResponseテンプレートにコンテキストを送信する代わりに、ビューでDjangoビューが返すオブジェクトにzipアーカイブを書き込むようにすることができます。最後に、ブラウザに応答をファイルとして処理するように指示するには、mimetypeを適切な形式に設定する必要があります


6

models.py

from django.db import models

class PageHeader(models.Model):
    image = models.ImageField(upload_to='uploads')

views.py

from django.http import HttpResponse
from StringIO import StringIO
from models import *
import os, mimetypes, urllib

def random_header_image(request):
    header = PageHeader.objects.order_by('?')[0]
    image = StringIO(file(header.image.path, "rb").read())
    mimetype = mimetypes.guess_type(os.path.basename(header.image.name))[0]

    return HttpResponse(image.read(), mimetype=mimetype)

画像サイズのメモリ内文字列を作成するのは安全ではないようです。
dhill


5
def download_zip(request,file_name):
    filePath = '<path>/'+file_name
    fsock = open(file_name_with_path,"rb")
    response = HttpResponse(fsock, content_type='application/zip')
    response['Content-Disposition'] = 'attachment; filename=myfile.zip'
    return response

必要に応じて、zipおよびコンテンツタイプを置き換えることができます。


1
あなたが意味したことfsock = open(filePath,"rb")
stelios '22 / 08/22

4

メモリ内のtgzアーカイブと同じ:

import tarfile
from io import BytesIO


def serve_file(request):
    out = BytesIO()
    tar = tarfile.open(mode = "w:gz", fileobj = out)
    data = 'lala'.encode('utf-8')
    file = BytesIO(data)
    info = tarfile.TarInfo(name="1.txt")
    info.size = len(data)
    tar.addfile(tarinfo=info, fileobj=file)
    tar.close()

    response = HttpResponse(out.getvalue(), content_type='application/tgz')
    response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
    return response
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.