문제
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-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 스크립트는 적어도 내가 볼 수 있는 한 여기에 필요한 전부입니다.