Generieren einer Datei zum Herunterladen mit Django


96

Ist es möglich, ein Zip-Archiv zu erstellen und zum Herunterladen anzubieten, aber dennoch keine Datei auf der Festplatte zu speichern?

Antworten:


111

Um einen Download auszulösen, müssen Sie den Content-DispositionHeader festlegen :

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

Wenn Sie die Datei nicht auf der Festplatte haben möchten, müssen Sie sie verwenden StringIO

import cStringIO as StringIO

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

Optional können Sie auch den Content-LengthHeader festlegen :

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

1
Ich denke, Content-Length könnte automatisch mit Django Middleware passieren
andrewrk

4
Anhand dieses Beispiels wird eine Datei heruntergeladen, die immer leer ist. Irgendwelche Ideen?
camelCase

3
Wie @ eleaz28 sagte, wurden auch in meinem Fall leere Dateien erstellt. Ich habe das gerade entfernt FileWrapperund es hat funktioniert.
Sébastien Deprez

Diese Antwort funktioniert nicht mit Django 1.9: siehe dies: stackoverflow.com/a/35485073/375966
Afshin Mehrabani

1
Ich habe meine Datei im Lesemodus geöffnet, dann gibt file.getvalue () einen Attributfehler aus: TextIOWrapper hat kein Attribut getValue.
Shubham Srivastava

26

Sie werden glücklicher sein, eine temporäre Datei zu erstellen. Das spart viel Speicher. Wenn Sie mehr als einen oder zwei Benutzer gleichzeitig haben, ist die Speichereinsparung sehr, sehr wichtig.

Sie können jedoch in ein StringIO- Objekt schreiben .

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

Das "Puffer" -Objekt ist dateiähnlich mit einem 778-Byte-ZIP-Archiv.


2
Guter Punkt zum Speichern von Speicher. Aber wenn Sie eine temporäre Datei verwenden, wo würden Sie den Code ablegen, um sie zu löschen?
Andrewrk

@ superjoe30: regelmäßige Bereinigungsjobs. Django verfügt bereits über einen Administratorbefehl, der regelmäßig ausgeführt werden muss, um alte Sitzungen zu entfernen.
S.Lott

@ Superjoe30 das ist, was / tmp ist für :)
Aehlke

@ S.Lott Ist es möglich, die erstellte Datei (in Ihrem Beispiel z in) mit mod x-sendfile bereitzustellen?
Miind

10

Warum nicht stattdessen eine TAR-Datei erstellen? Wie so:

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
Für eine neuere Version von Django sollten Sie content_type=anstelle vonmimetype=
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)

Sieht unsicher aus, um eine speicherinterne Zeichenfolge mit Bildgröße zu erstellen.
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

Sie können die Postleitzahl und den Inhaltstyp gemäß Ihren Anforderungen ersetzen.


1
Du fsock = open(filePath,"rb")
meintest

4

Gleiches gilt für das tgz-Archiv im Speicher:

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.