Django ile indirmek için dosya oluşturma


96

Bir zip arşivi oluşturup indirmeyi teklif etmek mümkün, ancak yine de bir dosyayı sabit sürücüye kaydetmiyor mu?

Yanıtlar:


112

Bir indirmeyi tetiklemek için Content-Dispositionbaşlığı ayarlamanız gerekir :

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

Dosyayı diskte istemiyorsanız kullanmanız gerekir StringIO

import cStringIO as StringIO

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

İsteğe bağlı Content-Lengtholarak başlığı da ayarlayabilirsiniz :

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

1
Bence Content-Length, Django ara yazılımıyla otomatik olarak gerçekleşebilir
andrewrk

4
Bu örneği kullanarak her zaman boş olan bir dosya indirir, herhangi bir fikriniz var mı?
camelCase

3
@ Eleaz28'in dediği gibi, benim durumumda da boş dosyalar oluşturuyordu. Sadece kaldırdım FileWrapperve işe yaradı.
Sébastien Deprez

Bu cevap Django 1.9 ile çalışmıyor: buna bakın: stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
Dosyamı okuma modunda açtım ve file.getvalue () öznitelik hatası veriyor: TextIOWrapper'ın getValue özniteliği yok.
Shubham Srivastava

25

Geçici bir dosya oluşturmaktan daha mutlu olacaksınız. Bu, çok fazla bellek tasarrufu sağlar. Aynı anda birden fazla veya iki kullanıcınız olduğunda, bellek tasarrufunun çok, çok önemli olduğunu göreceksiniz.

Bununla birlikte, bir StringIO nesnesine yazabilirsiniz .

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

"Tampon" nesnesi, 778 baytlık bir ZIP arşiviyle dosya gibidir.


2
Bellek tasarrufu konusunda iyi bir nokta. Ancak geçici bir dosya kullanıyorsanız, onu silmek için kodu nereye koyarsınız?
andrewrk

@ superjoe30: periyodik temizlik işleri. Django'nun eski oturumları kaldırmak için periyodik olarak çalıştırılması gereken bir admin komutu zaten var.
S.Lott

@ superjoe30 işte / tmp bunun içindir :)
aehlke

@ S.Lott Oluşturulan dosyayı (örneğinizde z) mod x-sendfile kullanarak sunmak mümkün müdür?
Amir Afianian

10

Neden bunun yerine bir tar dosyası yapmıyorsunuz? Şöyle:

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'nun daha yeni sürümü için, content_type=yerine sahip olmalısınızmimetype=
Guillaume Lebreton


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)

Bellek içi görüntü boyutunda bir dizi oluşturmak güvenli görünmüyor.
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 ve içerik türünü ihtiyacınıza göre değiştirebilirsiniz.


1
Sen demekfsock = open(filePath,"rb")
stelios

4

Bellek tgz arşiviyle aynı:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.