문제

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

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

도움이 되었습니까?

해결책

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

Python 모듈 사용 압축 파일 zip 아카이브를 생성하려면 파일이 지정하는대로 스트링IO 객체(ZipFile 생성자는 파일류 객체가 필요합니다).압축하려는 파일을 추가하세요.그런 다음 Django 애플리케이션에서 StringIO 객체의 내용을 반환합니다. HttpResponse MIME 유형이 다음으로 설정됨 application/x-zip-compressed (아니면 적어도 application/octet-stream).원하시면 설정하시면 됩니다 content-disposition 헤더이지만 실제로는 필수가 아닙니다.

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

다른 팁

이를 수행하는 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

여기에 많은 답변을 사용하는 것이 좋습니다 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

Python3의 경우 다음을 사용합니다. io.바이트IO ~부터 스트링IO 이를 달성하기 위해 더 이상 사용되지 않습니다.도움이 되길 바랍니다.

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는 동적 콘텐츠(특히 Zip 파일) 생성을 직접 처리하지 않습니다.그 작업은 Python의 표준 라이브러리에 의해 수행됩니다.Python에서 Zip 파일을 동적으로 생성하는 방법을 살펴볼 수 있습니다. 여기.

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

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

뻔뻔한 플러그:당신이 사용할 수있는 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]

나는 사용했다 장고 2.0 그리고 파이썬 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

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

(저는 개발과 관련이 없습니다.그냥 사용해 볼 생각입니다.)

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

장점:

  • django 미디어 메커니즘을 사용하여 정적 zip 파일을 제공합니다(일반적인 업로드와 유사).
  • 일반 cron 스크립트 실행을 통해 오래된 zip 파일을 정리하는 기능(zip 파일 모델의 날짜 필드를 사용할 수 있음)

"zip 서버"에 대한 링크를 작성할 수는 없나요?zip 아카이브 자체가 Django에서 제공되어야 하는 이유는 무엇입니까?zip을 생성하고 이를 stdout에 저장하는 90년대 CGI 스크립트는 적어도 내가 볼 수 있는 한 여기에 필요한 전부입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top