8

我需要在 Django 中提供 Web 请求时启动一个 pdftk 进程,然后等待它完成。我当前的 pdftk 代码如下所示:

proc = subprocess.Popen(["/usr/bin/pdftk", 
                         "/tmp/infile1.pdf", 
                         "/tmp/infile2.pdf", 
                         "cat", "output", "/tmp/outfile.pdf"])    
proc.communicate()

只要我在开发服务器下执行(以用户身份运行www-data),这工作正常。但是,一旦我切换到 mod_wsgi,不做任何更改,代码就会挂在 处proc.communicate(),并且“outfile.pdf”被保留为长度为零的打开文件句柄。

我已经尝试了子进程调用的几种变体(以及普通的旧 os.system)——将 stdin/stdout/stderr 设置为 PIPE 或各种文件句柄没有任何改变。使用“shell=True”可以防止proc.communicate()挂起,但是 pdftk 无法在 devserver 或 mod_wsgi 下创建输出文件。 这个讨论似乎表明操作系统信号和 pdftk 可能存在一些我不理解的更深层次的巫术。

是否有任何解决方法可以让这样的子进程调用在 wsgi 下正常工作?我避免使用 PyPDF 来合并 pdf 文件,因为我必须合并足够多的文件(数百个)以致内存不足(PyPDF 需要在合并时保持每个源 pdf 文件在内存中打开)。

我在最近的 Ubuntu、pythons 2.6 和 2.7 下这样做。

4

2 回答 2

8

尝试使用绝对文件系统路径来输入和输出文件。Apache 下的当前工作目录与运行服务器的目录不同,可以是任何目录。


消除明显的后的第二次尝试。

pdftk 程序是一个 Java 程序,它依靠能够生成/接收 SIGPWR 信号来触发垃圾收集或执行其他操作。问题是在守护进程模式下的 Apache/mod_wsgi 下,信号在请求处理程序线程中被阻塞,以确保它们仅由寻找进程关闭触发事件的主线程接收。当您派生进程以运行 pdftk 时,不幸的是,它从请求处理程序线程继承了阻塞的 sigmask。这样做的后果是它阻碍了 Java 垃圾收集过程的运行,并导致 pdftk 以奇怪的方式失败。

唯一的解决方案是使用 Celery 并让前端向 Celery 队列提交作业,以便 celeryd 然后分叉并执行 pdftk。因为这是从与 Apache 不同的进程创建的,所以您不会遇到这个问题。

有关 mod_wsgi 和 pdftk 的更多详细信息,尤其是在 Google Groups 中。

http://groups.google.com/group/modwsgi/search?group=modwsgi&q=pdftk&qt_g=Search+this+group

于 2011-09-25T04:33:29.587 回答
0

更新:在 Python 3 上使用 Pdftk 将两个 Pdfs 合并在一起:

自从这个问题发布以来已经有好几年了。(2011)。原始海报说,当他们运行旧版本的 python 时, os.system对他们不起作用:

  • Python 2.6
  • 蟒蛇 2.7

Python 3.4上, os.system为我工作:

  • 导入操作系统
  • os.system("pdftk"+ template_file +"fill_form"+ data_file +"输出"+ export_file )

Python 3.5添加了subprocess.run

  • subprocess.run ("pdftk" + template_file + "fill_form" + data_file + "output" + export_file )

  • 我为我的文件使用了绝对路径:

    • template_file = "/var/www/myproject/static/"

我用 Django 1.10 运行它,结果输出被保存到export_file

如何合并两个 PDF 并显示 PDF 输出:

from django.http import HttpResponse, HttpResponseNotFound
from django.core.files.storage import FileSystemStorage
from fdfgen import forge_fdf
import os

template_file = = "/var/www/myproject/template.pdf"
data_file = "/var/www/myproject/data.fdf"
export_file ="/var/www/myproject/pdf_output.pdf"

fields = {}
fields['organization_name'] = organization_name
fields['address_line_1'] = address_line_1
fields['request_date'] = request_date
fields['amount'] = amount
field_list = [(field, fields[field]) for field in fields]

fdf = forge_fdf("",field_list,[],[],[])
fdf_file = open(data_file,"wb")
fdf_file.write(fdf)
fdf_file.close()

os.system("pdftk " + template_file + " fill_form " + data_file + " output " + export_file)
time.sleep(1)

fs = FileSystemStorage()
if fs.exists(export_file):
  with fs.open(export_file) as pdf:
    return HttpResponse(pdf, content_type='application/pdf; charset=utf-8')
else:
    return HttpResponseNotFound('The requested pdf was not found in our server.')

图书馆:

于 2017-03-24T12:39:09.990 回答