如何在Django中返回生成的巨大ZIP文件?

2024-05-06 06:28:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我想返回一个在Django中生成的非常大的ZIP文件。ZIP将包含1000到5000个PDF文件

这些PDF文件存储在AmazonS3上

我正在使用Heroku,它有30秒的超时时间。所以我无法获取所有文件并及时发送响应

我尝试的是在后端生成ZIP文件,我没有这个超时限制。但是Heroku有1GB的内存限制。所以我也不能这么做

这是我用来执行此任务的代码:

from zipfile import ZipFile

def make_incoming_zip_file():
    zip_obj = ZipFileIncomingInvoices.objects.get(zip_file="")
    invoices = get_invoices(year, quarter)

    with ZipFile("invoices.zip", "w") as zf:
        for idx, invoice in enumerate(invoices):
            file_path = "work_folder/incoming_invoice.pdf"

            with open(file_path , "wb") as f:
                f.write(invoice.invoice_file.read())
            zf.write(filename=file_path , arcname=f"{idx+1} {invoice}.pdf")

    zip_obj.zip_file = File(open("invoices.zip", "rb"))
    zip_obj.save()

实现这项任务的最佳方式是什么

多谢各位


Tags: 文件pathobjgetherokupdfaswith
1条回答
网友
1楼 · 发布于 2024-05-06 06:28:04

如果您使用S3、Django和Heroku,那么实际上下载大文件是不可能的,因为Heroku上有30秒的超时。所以你有三个选择

第一个是直接使用boto3 API生成允许公共文件下载的url。方法是^{}

s3 = boto3.client('s3')

# Generate the URL to get 'mykey' from 'bucket-name'
url = s3.generate_presigned_url(
    ClientMethod='get_object',
    Params={
        'Bucket': 'mybucket',
        'Key': 'mykey'
    },
    expires=86400
)

^{}文件中解释

第二个是做同样的事情,但是使用boto3django-storages。它添加了一个很好的抽象层,但这是另一个需要学习和配置的层,但如果您使用Django和S3还没有使用它,我会感到惊讶

范例

d = Document.objects.last()
d.upload.storage.bucket.meta.client.generate_presigned_url('get_object', Params={'Bucket': 'mybucket', 'Key': 'mykey'})

对于这两种解决方案,您可以生成临时令牌,这些令牌将在几毫秒内使这些URL过期

第三种解决方案是在Heroku上运行Redis并创建一个芹菜任务,该任务将由

  • 从s3下载文件
  • 拉链
  • 将它们保存在内存中/保存到s3中
  • 将相关url发送给用户,使其能够下载压缩包

这样,您可能不会遇到超时问题,但内存可能是一个问题,这取决于您的动态对象、文件和流量。 但它可能会增加您的成本、架构,而且根据上述条件,它可能并不总能解决您的问题

相关问题 更多 >