关于python:在Django中提供动态生成的ZIP存档

关于python:在Django中提供动态生成的ZIP存档

Serving dynamically generated ZIP archives in Django

如何在Django中为用户提供动态生成的ZIP存档?

我正在建立一个站点,用户可以在其中选择可用书籍的任意组合,并将其下载为ZIP存档。 我担心为每个请求生成这样的存档会降低我的服务器的爬网速度。 我还听说Django当前尚没有很好的解决方案来提供动态生成的文件。


解决方法如下。

使用Python模块zipfile创建zip存档,但是在文件中指定StringIO对象(ZipFile构造函数需要类似文件的对象)。添加您要压缩的文件。然后在Django应用程序中,将HttpResponse中的StringIO对象的内容返回,且mimetype设置为application/x-zip-compressed(或至少为application/octet-stream)。如果需要,可以设置content-disposition标头,但这并不是真正需要的。

但是请注意,在每个请求上创建zip存档都是一个坏主意,这可能会杀死您的服务器(如果存档很大,则不计算超时)。基于性能的方法是将生成的输出缓存在文件系统中的某个位置,并仅在源文件已更改时才重新生成它。更好的主意是预先准备存档(例如,按cron作业),并让您的Web服务器将其作为常规静态变量来提供。


这是执行此操作的Django视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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


这里有许多答案建议使用StringIOBytesIO缓冲区。但是,这不是必需的,因为HttpResponse已经是一个类似于文件的对象:

1
2
3
4
5
6
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.ByteIO,因为不推荐使用StringIO来实现此目的。希望能帮助到你。

1
2
3
4
5
6
7
8
9
10
11
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 2.0和Python 3.6。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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


无耻的插件:您可以将django-zipview用于相同的目的。

pip install django-zipview之后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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]

该模块生成并流式传输存档:https://github.com/allanlei/python-zipstream

(我没有与开发联系。只是考虑使用它。)


我建议使用单独的模型来存储这些临时zip文件。您可以即时创建zip,使用filefield保存到模型,最后将url发送给用户。

好处:

  • 使用django媒体机制(例如,通常的上传)提供静态zip文件。
  • 能够通过定期执行cron脚本清除过时的zip文件(可以使用zip文件模型中的日期字段)。

您不能只写一个指向" zip服务器"的链接吗?为什么zip存档本身需要从Django提供?至少在我看来,这里确实需要90年代的CGI脚本来生成一个zip并将其吐出到stdout。


推荐阅读

    linux命令暂停下载?

    linux命令暂停下载?,系统,代码,暂停,第一,服务,管理,命令,进程,程序,接线,lin

    linux命令下载工具?

    linux命令下载工具?,工具,网络,代理,代码,简介,位置,系统,第一,下载工具,文

    配置网关的命令linux?

    配置网关的命令linux?,地址,系统,网络,代码,信息,环境,命令,网关,服务,电脑,

    linux下载打包命令行?

    linux下载打包命令行?,软件,系统,名称,工具,官网,文件,命令,目录,下面,表示,l

    linux命令行大全下载?

    linux命令行大全下载?,系统,地址,工作,信息,管理,技术,命令,名家,评论,数据,

    linux命令下载jdk?

    linux命令下载jdk?,官网,系统,地址,工作,工具,服务,管理,环境,网上,地方,怎样

    linux中的下载命令行?

    linux中的下载命令行?,软件,系统,网络,电脑,名称,密码,官网,位置,服务,代理,l

    linux命令行大全下载?

    linux命令行大全下载?,系统,地址,工作,信息,管理,技术,命令,名家,评论,数据,

    linux命令下载jdk?

    linux命令下载jdk?,官网,系统,地址,工作,工具,服务,管理,环境,网上,地方,怎样

    linux服务器下载命令?

    linux服务器下载命令?,服务,密码,系统,档案,工具,网络,公共,百度,地址,认证,l

    linux查询网关命令?

    linux查询网关命令?,网络,信息,地址,环境,系统,网关,名字,中心,状态,命令,lin

    linux多线程下载命令?

    linux多线程下载命令?,软件,工具,平台,中心,系统,代理,网络,网站,手机,官方

    linux下载转发命令?

    linux下载转发命令?,平台,工具,密码,服务,软件,认证,网络,代理,设备,电脑,从l

    linux下载安装包命令?

    linux下载安装包命令?,软件,系统,名称,位置,数据,名字,通讯,灵活,最新,管理,

    linux怎么看网关命令?

    linux怎么看网关命令?,地址,网络,系统,信息,电脑,网关,命令,终端,环境,中心,D

    linux下载步骤命令?

    linux下载步骤命令?,系统,软件,网络,电脑,官网,名称,管理,工具,位置,盘中,安

    linux各种下载命令?

    linux各种下载命令?,软件,系统,网络,工具,代理,名称,中心,环境,百度,市场,Lin

    linux下载包的命令是?

    linux下载包的命令是?,软件,系统,工具,网络,平台,名称,服务,手机,位置,在线,

    linux清除网关命令?

    linux清除网关命令?,网络,信息,环境,网关,命令,产品,地址,官网,基础,终端,华

    linux配网关的命令?

    linux配网关的命令?,网络,地址,信息,环境,系统,工具,网关,命令,服务,终端,Lin