Est-il possible de créer une archive zip et de la proposer au téléchargement, mais toujours pas d'enregistrer un fichier sur le disque dur?
Réponses:
Pour déclencher un téléchargement, vous devez définir l'en- Content-Disposition
tête:
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
Si vous ne voulez pas le fichier sur le disque, vous devez utiliser StringIO
import cStringIO as StringIO
myfile = StringIO.StringIO()
while not_finished:
# generate chunk
myfile.write(chunk)
En option, vous pouvez également définir l'en- Content-Length
tête:
response['Content-Length'] = myfile.tell()
FileWrapper
, et cela a fonctionné.
Vous serez plus heureux de créer un fichier temporaire. Cela économise beaucoup de mémoire. Lorsque vous avez plus d'un ou deux utilisateurs simultanément, vous constaterez que l'économie de mémoire est très, très importante.
Vous pouvez cependant écrire dans un objet StringIO .
>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778
L'objet "buffer" est semblable à un fichier avec une archive ZIP de 778 octets.
Pourquoi ne pas créer un fichier tar à la place? Ainsi:
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
content_type=
place demimetype=
Oui, vous pouvez utiliser le module zipfile , module zlib ou d' autres modules de compression pour créer une archive zip en mémoire. Vous pouvez faire en sorte que votre vue écrive l'archive zip sur l' HttpResponse
objet que la vue Django renvoie au lieu d'envoyer un contexte à un modèle. Enfin, vous devrez définir le type MIME au format approprié pour indiquer au navigateur de traiter la réponse comme un fichier .
from django.db import models
class PageHeader(models.Model):
image = models.ImageField(upload_to='uploads')
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)
Il y a un exemple de code à http://djangosnippets.org/snippets/365/
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
Vous pouvez remplacer le zip et le type de contenu selon vos besoins.
fsock = open(filePath,"rb")
Idem avec l'archive tgz en mémoire:
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