it-swarm-ko.com

Django에서 동적으로 생성 된 Zip 아카이브 제공

Django에서 동적으로 생성 된 Zip 아카이브를 사용자에게 제공하는 방법은 무엇입니까?

사용자가 사용 가능한 책의 조합을 선택하고 Zip 아카이브로 다운로드 할 수있는 사이트를 만들고 있습니다. 각 요청에 대해 이러한 아카이브를 생성하면 서버가 크롤링되는 속도가 느려 질까 걱정됩니다. 나는 또한 Django 현재 동적으로 생성 된 파일을 제공하기위한 좋은 솔루션이 없다고 들었습니다.

55
zuber

해결책은 다음과 같습니다.

Python module zipfile 을 사용하여 Zip 아카이브를 만들지 만 파일로 StringIO 개체를 지정합니다 (ZipFile 생성자는 파일과 유사한 개체가 필요함). 그런 다음 Django 응용 프로그램에서 mimetype이 application/x-Zip-compressed (또는 최소한 application/octet-stream). 원하는 경우 content-disposition 헤더를 설정할 수 있지만 꼭 필요한 것은 아닙니다.

그러나 각 요청에 대해 Zip 아카이브를 만드는 것은 나쁜 생각이며 이로 인해 서버가 종료 될 수 있습니다 (아카이브가 큰 경우 시간 초과를 계산하지 않음). 성능 측면에서는 생성 된 출력을 파일 시스템의 어딘가에 캐시하고 소스 파일이 변경된 경우에만 다시 생성하는 것입니다. 더 나은 아이디어는 사전에 아카이브를 준비하고 (예 : cron 작업으로) 웹 서버가이를 일반적인 통계로 제공하도록하는 것입니다.

42
zgoda

다음은이를 수행하는 Django보기입니다.

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
40
dbr

여기에있는 많은 답변은 StringIO 또는 BytesIO 버퍼를 사용하도록 제안합니다. 그러나 HttpResponse은 (는) 이미 파일과 유사한 객체이므로 필요하지 않습니다.

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
13
Antoine Pinsard

Python3의 경우 StringIO이 작업을 수행하기 위해 더 이상 사용되지 않기 때문에 io.ByteIO 사용합니다. 도움이되기를 바랍니다.

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
7
pitaside

Django는 동적 콘텐츠 (특히 Zip 파일) 생성을 직접 처리하지 않습니다. 이 작업은 Python의 표준 라이브러리에서 수행됩니다. Python here 에서 Zip 파일을 동적으로 만드는 방법을 살펴볼 수 있습니다.

서버 속도가 느려지는 것이 걱정된다면 동일한 요청이 많을 것으로 예상되면 요청을 캐시 할 수 있습니다. Django의 캐시 프레임 워크 를 사용하여 도움을 줄 수 있습니다.

전반적으로 압축 파일은 CPU 집약적 일 수 있지만 Django는 다른 Python 웹 프레임 워크)보다 느려서는 안됩니다.

6
Cristian

Django 2.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
5
Pasha Mok

뻔뻔한 플러그 : 동일한 목적으로 Django-zipview 를 사용할 수 있습니다.

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]
5
Thibault J

이 모듈은 아카이브를 생성하고 스트리밍합니다. https://github.com/allanlei/python-zipstream

(나는 개발과 관련이 없습니다. 단지 그것을 사용하려고 생각합니다.)

3
Risadinha

임시 Zip 파일을 저장하기 위해 별도의 모델을 사용하는 것이 좋습니다. 즉시 Zip을 생성하고 파일 필드로 모델에 저장하고 마지막으로 사용자에게 URL을 보낼 수 있습니다.

장점 :

  • Django 미디어 메커니즘 (일반 업로드와 유사)으로 정적 Zip 파일 제공).
  • 정기적 인 cron 스크립트 실행 (Zip 파일 모델의 날짜 필드 사용 가능)을 통해 오래된 Zip 파일을 정리하는 기능.
1
carefulweb

그냥 "Zip 서버"에 대한 링크를 쓸 수 없습니까? Django에서 Zip 아카이브 자체를 제공해야하는 이유는 무엇입니까? Zip을 생성하고 stdout에 뱉어내는 90 년대 CGI 스크립트는 최소한 내가 볼 수있는 한 여기서 필요한 모든 것입니다.

0
Andy Ross