Czy można utworzyć archiwum zip i zaoferować je do pobrania, ale nadal nie można zapisać pliku na dysku twardym?
Odpowiedzi:
Aby uruchomić pobieranie, musisz ustawić Content-Disposition
nagłówek:
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
Jeśli nie chcesz pliku na dysku, musisz użyć StringIO
import cStringIO as StringIO
myfile = StringIO.StringIO()
while not_finished:
# generate chunk
myfile.write(chunk)
Opcjonalnie możesz również ustawić Content-Length
nagłówek:
response['Content-Length'] = myfile.tell()
FileWrapper
i zadziałało.
Będziesz szczęśliwszy, tworząc plik tymczasowy. Oszczędza to dużo pamięci. Kiedy masz więcej niż jednego lub dwóch użytkowników jednocześnie, zauważysz, że oszczędzanie pamięci jest bardzo, bardzo ważne.
Możesz jednak pisać do obiektu StringIO .
>>> import zipfile
>>> import StringIO
>>> buffer= StringIO.StringIO()
>>> z= zipfile.ZipFile( buffer, "w" )
>>> z.write( "idletest" )
>>> z.close()
>>> len(buffer.getvalue())
778
Obiekt "bufor" jest podobny do pliku z 778-bajtowym archiwum ZIP.
Dlaczego zamiast tego nie utworzyć pliku tar? Tak jak to:
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=
zamiast tegomimetype=
Tak, można użyć modułu zipfile , moduł zlib lub innych modułów kompresji aby utworzyć archiwum zip w pamięci. Możesz sprawić, by widok zapisywał archiwum zip do HttpResponse
obiektu, który zwraca widok Django, zamiast wysyłać kontekst do szablonu. Na koniec musisz ustawić typ MIME na odpowiedni format, aby poinstruować przeglądarkę, aby traktowała odpowiedź jako plik .
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)
Przykład kodu znajduje się pod adresem 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
Możesz zastąpić kod pocztowy i typ zawartości zgodnie z wymaganiami.
fsock = open(filePath,"rb")
To samo z archiwum tgz w pamięci:
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