Generazione di file da scaricare con Django


96

È possibile creare un archivio zip e offrirlo per il download, ma non salvare ancora un file sul disco rigido?

Risposte:


111

Per attivare un download è necessario impostare l' Content-Dispositionintestazione:

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

Se non vuoi il file su disco devi usare StringIO

import cStringIO as StringIO

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

Facoltativamente puoi impostare anche l' Content-Lengthintestazione:

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

1
Penso che Content-Length possa accadere automaticamente con il middleware Django
andrewrk

4
Utilizzando questo esempio viene scaricato un file che è sempre vuoto, qualche idea?
camelCase

3
Come ha detto @ eleaz28, anche nel mio caso creava file vuoti. Ho appena rimosso il FileWrapper, e ha funzionato.
Sébastien Deprez

Questa risposta non funziona con Django 1.9: vedi questo: stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
Ho aperto il mio file in modalità di lettura, quindi file.getvalue () sta dando un errore di attributo: TextIOWrapper non ha attributi getValue.
Shubham Srivastava

26

Sarai più felice di creare un file temporaneo. Ciò consente di risparmiare molta memoria. Quando hai più di uno o due utenti contemporaneamente, scoprirai che il risparmio di memoria è molto, molto importante.

È tuttavia possibile scrivere su un oggetto StringIO .

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

L'oggetto "buffer" è simile a un file con un archivio ZIP da 778 byte.


2
Buon punto sul risparmio di memoria. Ma se utilizzi un file temporaneo, dove metteresti il ​​codice per eliminarlo?
andrewrk

@ superjoe30: lavori di pulizia periodici. Django ha già un comando di amministrazione che deve essere eseguito periodicamente per rimuovere le vecchie sessioni.
S.Lott

@ superjoe30 questo è ciò che / tmp è per :)
aehlke

@ S.Lott È possibile servire il file creato (z nel tuo esempio) usando mod x-sendfile?
Miind

10

Perché invece non creare un file tar? Così:

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
Per la versione più recente di Django, dovresti avere al content_type=posto dimimetype=
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)

Non sembra sicuro creare una stringa in memoria delle dimensioni dell'immagine.
discesa


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

È possibile sostituire zip e tipo di contenuto secondo le proprie esigenze.


1
fsock = open(filePath,"rb")
Volevi

4

Lo stesso con l'archivio tgz in memoria:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.