Frage

Wie dienen Benutzern dynamisch generierte ZIP-Archiv in Django?

Ich mache eine Website, in der Benutzer jede Kombination der verfügbaren Bücher auswählen und sie als ZIP-Archiv herunterladen. Ich mache mir Sorgen, dass für jede Anforderung solcher Archive zu erzeugen würde meinen Server verlangsamen, um ein Crawling nach unten. Ich habe auch gehört, dass Django derzeit nicht eine gute Lösung hat dynamisch generierten Dateien zu dienen.

War es hilfreich?

Lösung

Die Lösung ist wie folgt.

Mit Python-Modul zipfile Zip-Archiv zu erstellen, sondern als Datei angeben StringIO Objekt (ZipFile Konstruktor erfordert dateiähnliche Objekt) . Hinzufügen von Dateien Sie komprimieren möchten. Dann in Ihrer Django-Anwendung zurückzukehren, den Inhalt StringIO Objekts in HttpResponse mit MIME-Typ auf application/x-zip-compressed (oder zumindest application/octet-stream). Wenn Sie möchten, können Sie content-disposition Header gesetzt, aber das ist nicht wirklich erforderlich werden sollte.

Aber Vorsicht, auf jede Anfrage Zip-Archive zu schaffen ist eine schlechte Idee, und dies kann der Server (ohne Timeouts, wenn die Archive groß sind) zu töten. Performance-weise Ansatz generierte Ausgabe irgendwo im Dateisystem zwischengespeichert werden und regenerieren es nur dann, wenn Quelldateien geändert haben. Noch bessere Idee ist, Archive im Voraus vorzubereiten (z. B. durch cron-Job) und haben Ihren Webserver sie wie gewohnt Statik dienen.

Andere Tipps

Hier ist eine Django-Ansicht, dies zu tun:

import os
import zipfile
import StringIO

from django.http import HttpResponse


def getfiles(request):
    # Files (local path) to put in the .zip
    # FIXME: Change this (get paths from DB etc)
    filenames = ["/tmp/file1.txt", "/tmp/file2.txt"]

    # Folder name in ZIP archive which contains the above files
    # E.g [thearchive.zip]/somefiles/file2.txt
    # FIXME: Set this to something better
    zip_subdir = "somefiles"
    zip_filename = "%s.zip" % zip_subdir

    # Open StringIO to grab in-memory ZIP contents
    s = StringIO.StringIO()

    # The zip compressor
    zf = zipfile.ZipFile(s, "w")

    for fpath in filenames:
        # Calculate path for file in zip
        fdir, fname = os.path.split(fpath)
        zip_path = os.path.join(zip_subdir, fname)

        # Add file, at correct path
        zf.write(fpath, zip_path)

    # Must close zip for all contents to be written
    zf.close()

    # Grab ZIP file from in-memory, make response with correct MIME-type
    resp = HttpResponse(s.getvalue(), mimetype = "application/x-zip-compressed")
    # ..and correct content-disposition
    resp['Content-Disposition'] = 'attachment; filename=%s' % zip_filename

    return resp

Viele Antworten hier schlagen einen StringIO oder BytesIO Puffer zu verwenden. Dies ist jedoch nicht erforderlich, da HttpResponse bereits ein Datei-ähnliche Objekt:

response = HttpResponse(content_type='application/zip')
zip_file = zipfile.ZipFile(response, 'w')
for filename in filenames:
    zip_file.write(filename)
response['Content-Disposition'] = 'attachment; filename={}'.format(zipfile_name)
return response

Für python3 i die io.ByteIO da StringIO ist veraltet, dies zu erreichen. Hoffe, es hilft.

import io

def my_downloadable_zip(request):
    zip_io = io.BytesIO()
    with zipfile.ZipFile(zip_io, mode='w', compression=zipfile.ZIP_DEFLATED) as backup_zip:
        backup_zip.write('file_name_loc_to_zip') # u can also make use of list of filename location
                                                 # and do some iteration over it
     response = HttpResponse(zip_io.getvalue(), content_type='application/x-zip-compressed')
     response['Content-Disposition'] = 'attachment; filename=%s' % 'your_zipfilename' + ".zip"
     response['Content-Length'] = zip_io.tell()
     return response

Django nicht direkt die Erzeugung von dynamischen Inhalten verarbeiten (insbesondere Zip-Dateien). Diese Arbeit würde von Pythons Standardbibliothek durchgeführt werden. Sie können einen Blick darauf werfen, wie eine Zip-Datei in Python dynamisch erstellen hier .

Wenn Sie sich Sorgen machen um es zu verlangsamen Ihren Server können Sie die Anfragen zwischenspeichern, wenn Sie viele der gleichen Anfragen zu erwarten. Sie können Django verwenden Cache Rahmen dabei zu helfen .

Insgesamt Dateien zippen CPU-intensiv sein kann, aber Django sollte nicht langsamer als ein anderer Python-Web-Framework sein.

Shameless Stecker. Sie können django-zipview für den gleichen Zweck

Nach einem pip install django-zipview:

from zipview.views import BaseZipView

from reviews import Review


class CommentsArchiveView(BaseZipView):
    """Download at once all comments for a review."""

    def get_files(self):
        document_key = self.kwargs.get('document_key')
        reviews = Review.objects \
            .filter(document__document_key=document_key) \
            .exclude(comments__isnull=True)

        return [review.comments.file for review in reviews if review.comments.name]

Ich habe Django 2.0 und Python 3.6 .

import zipfile
import os
from io import BytesIO

def download_zip_file(request):
    filelist = ["path/to/file-11.txt", "path/to/file-22.txt"]

    byte_data = BytesIO()
    zip_file = zipfile.ZipFile(byte_data, "w")

    for file in filelist:
        filename = os.path.basename(os.path.normpath(file))
        zip_file.write(file, filename)
    zip_file.close()

    response = HttpResponse(byte_data.getvalue(), content_type='application/zip')
    response['Content-Disposition'] = 'attachment; filename=files.zip'

    # Print list files in zip_file
    zip_file.printdir()

    return response

Dieses Modul erzeugt und Bächen ein Archiv: https://github.com/allanlei/python-zipstream

(Ich bin nicht mit der Entwicklung verbunden ist. Ich denke nur darüber verwenden.)

Ich schlage vor, zum Speichern dieser temporären Zip-Dateien separates Modell zu verwenden. Sie können Zip-on-fly erstellen, mit Filefield zu modellieren speichern und schließlich URL Benutzer senden.

Vorteile:

  • Serving statische ZIP-Dateien mit django Medien-Mechanismus (wie üblich Uploads).
  • Möglichkeit zur Bereinigung abgestanden Zip-Dateien durch regelmäßige cron Skriptausführung (das Datumsfeld von Zip-Datei-Modell verwenden kann).

Sie können nicht nur einen Link zu einem „zip-Server“ oder Dingsbums schreiben? Warum wird die Zip-Archiv müssen sich von Django bedient werden? Ein 90-Ära CGI-Skript ein Zip zu generieren und an stdout zu spucken ist wirklich alles, was hier, zumindest was erforderlich ist, wie ich sehen kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top