【问题标题】:Generate pdf files with Weasyprint, save in zip file, send that zip file to client and present it for download使用 Wea​​syprint 生成 pdf 文件,保存为 zip 文件,将该 zip 文件发送给客户端并呈现以供下载
【发布时间】:2017-02-07 22:14:38
【问题描述】:

让我分解一下我的要求。这就是我现在正在做的事情。

1.从 HTML 生成 PDF 文件

为此,我使用 Wea​​syprint 如下:

lstFileNames = []
for i, content in enumerate(lstHtmlContent):
    repName = 'report'+ str(uuid.uuid4()) + '.pdf'
    lstFileNames.append("D:/Python/Workspace/" + repName)

    HTML(string=content).write_pdf(target=repName,
        stylesheets=[CSS(filename='/css/bootstrap.css')])

所有文件名和路径都保存在lstFileNames

2。使用 weasyprint 生成的 pdf 文件创建一个 zip 文件

为此,我正在使用 zipfile

zipPath = 'reportDir' + str(uuid.uuid4()) + '.zip'
myzip = zipfile.ZipFile(zipPath, 'w') 
with  myzip:
    for f in lstFileNames:
        myzip.write(f)

3.将 zip 文件发送到客户端以供下载

resp = HttpResponse(myzip, content_type = "application/x-zip-compressed")

resp['Content-Disposition'] = 'attachment; filename=%s' % 'myzip.zip'

4.通过 Javascript 打开文件以进行下载

var file = new Blob([response], {type: 'application/x-zip-compressed'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);

问题

1.虽然前端成功接收到zip文件,但我尝试打开后,出现以下错误:

存档格式未知或已损坏

是我发送的文件有误还是我的 Javascript 代码有问题?

2. 有没有办法将所有 pdf 文件存储在字节数组列表中,并使用这些字节数组生成 zip 文件并将其发送给客户端?我用 weasyprint 试过了,但结果是一样的damaged file

3. 不完全是问题,但我无法在 weasyprint 文档中找到它。我可以强制保存文件的路径吗?

问题 #1 是最重要的,其余是次要的。我想知道我是否做得对,即生成 pdf 文件并将其 zip 文件发送给客户端。

提前致谢。

【问题讨论】:

  • 你能打开服务器上的zip文件吗?
  • 我可以手动打开它,方法是转到保存它的目录。其中的 PDF 文件也正在打开
  • 如果您只是重定向到 zip 文件的 url 会发生什么,例如window.location.href = 'link/to/file.zip';? (将 zip 文件移动到公开可用的 tmp 文件夹)
  • 它不起作用。我从服务器发送的不是 url

标签: javascript python django zipfile weasyprint


【解决方案1】:

稍微不同的方法是将 zip 文件移动到公共目录,然后将该位置发送到客户端(例如 json 格式),即:

publicPath = os.path.join('public/', os.path.basename(zipPath))
os.rename(zipPath, os.path.join('/var/www/', publicPath))

jsonResp = '{ "zip-location": "' + publicPath + '" }'

resp = HttpResponse(jsonResp, content_type = 'application/json');

然后在你客户端的javascript中:

var res = JSON.parse(response);
var zipFileUrl = '/' + res['zip-location'];

window.open(zipFileUrl, '_blank');

'/' + res['zip-location'] 假定您的页面与public 目录位于同一文件夹中(因此http://example.com/public/pdf-files-123.zip 指向您文件系统上的/var/www/public/pdf-files-123.zip)。

您可以使用 cron 作业清理 public 目录,该作业删除其中所有超过一小时左右的 .zip 文件。

【讨论】:

  • 注意:这个没有经过测试,只是给你一个想法
  • 这是我实际尝试的第一件事。将文件位置发送给客户端以打开。我不知道如何将D:/reports/report.zip 之类的绝对路径映射到http://127.0.0.1:8000/report.zip 之类的服务器路径。如果我按原样发送路径,它只会在 url 末尾添加绝对路径。
  • 如果只是本地使用,可以使用file protocol,即file:///D:/reports/report.zip。您使用什么服务器来托管 javascript?
【解决方案2】:

退出with 块后,文件句柄将关闭。您应该重新打开文件(这次打开)并使用read() 将内容传递给HttpResponse,而不是传递文件句柄本身。

with zipfile.ZipFile(zipPath, 'w') as myzip
    for f in lstFileNames:
        myzip.write(f)
with open(zipPath, 'r') as myzip:
    return HttpResponse(myzip.read(), content_type = "application/x-zip-compressed")

如果可行,那么您可以使用 StringIO 实例而不是文件句柄来存储 zip 文件。我不熟悉 Weasyprint,所以我不知道您是否可以使用 StringIO

【讨论】:

  • 打开文件并将其分配给 httpresponse 会出现错误:'charmap' codec can't decode byte 0x90 in position 194: character maps to <undefined>
  • 我通过在打开的文件行中添加 rb 来解决这个问题。现在它会打开给出unexpected end of archive 错误的 zip 文件
  • 你记得用myzip.read()吗?我在原始答案中说过要这样做,但在示例 sn-p 中错过了它。上面的例子对我有用。
  • 我之前没有添加myzip.read(),但是添加后错误也是一样的。你能检查我是否正确地用 Javascript 打开文件吗?
  • 抱歉,我无法帮助您调试 JavaScript。您应该在不使用 JavaScript 的情况下测试视图以找出问题所在。
猜你喜欢
  • 2011-01-18
  • 1970-01-01
  • 2019-07-08
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
  • 1970-01-01
相关资源
最近更新 更多