我问this one一个非常相似的问题。我正在Django的Ubuntu服务器上使用wkhtmltopdf创建一个pdf。
from tempfile import *
from subprocess import Popen, PIPE
tempfile = gettempdir()+"/results.pdf"
papersize = 'Tabloid'
orientation = 'Landscape'
command_args = "wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl %s" %(orientation, papersize, tempfile)
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
popen.terminate()
popen.wait()
response = HttpResponse(pdf_contents, mimetype='application/pdf')
return response
这使我在popen = Popen ...行上出现“没有这样的文件或目录”错误。所以我将该行更改为
popen = Popen(["sh", "-c", command_args], stdout=PIPE, stderr=PIPE)
现在我在pdf_contents = ...行上得到一个“'文件'对象不可调用”错误。
我也尝试将.communicate()添加到popen = ...行,但我似乎无法找到这样的pdf输出。我应该补充一点,在命令行输入command_args行可以很好地创建一个pdf。有人能指出我正确的方向吗?
答案 0 :(得分:3)
wkhtmltopdf
未输出Popen
的PDF内容进行阅读。 pdf_contents
正确包含命令的输出(无)。如果要将输出文件返回给客户端(见下文),则需要读取输出文件的内容,或跳过输出文件并使wkhtmltopdf
直接输出pdf的内容,
from tempfile import *
from subprocess import Popen, PIPE
tempfile = gettempdir()+"/results.pdf"
command_args = "/path/to/wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl %s" % ('Landscape', 'Tabloid', tempfile)
popen = Popen(["sh", "-c", command_args])
popen.wait()
f = open(tempfile, 'r')
pdf_contents = f.read()
f.close()
return HttpResponse(pdf_contents, mimetype='application/pdf')
答案 1 :(得分:2)
您的第一个版本失败,因为python不知道wkhtmltopdf位于何处。 Python不会检查你的路径。你的第二个版本将命令传递给一个shell来处理它。通过传递shell = True参数可以达到相同的效果。
第二个问题(正如其他人所说)是你不应该调用stdout()。
第三个问题是您的wkhtmltopdf命令错误。你在做:
wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl tempfile/results.pdf
相反,你应该传递
wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl -
这样wkhtmltopdf会将输出写入标准输出,你可以读取它。如果您传递另一个 - 作为源,您可以通过标准输入发送html。
答案 2 :(得分:1)
您获得'file' object is not callable
的原因是因为一旦您拥有popen
个对象,stdout
就是文件句柄,而不是方法。不要打电话,只需使用它:
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout.read()
答案 3 :(得分:1)
我意识到这不使用wkhtmltopdf,但我觉得这更清洁了。
查看https://docs.djangoproject.com/en/dev/howto/outputting-pdf/
答案 4 :(得分:0)
您可能需要考虑更改
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
# ...
response = ...
到
pdf_contents = subprocess.check_output(command_args.split())
response = ...
或旧版本:
process = Popen(command_args.split(), stdout=PIPE, stderr=PIPE)
pdf_contents = process.stdout.read()
response = ...
我建议你看一下check_output函数。
编辑:另外,不要调用terminate(),因为它会在不等待它完成的情况下终止进程,可能导致PDF损坏。您几乎只需要使用wait(),因为它将等待进程完成(因此输出所有它必须输出)。使用check_output()函数时,您不必担心它,因为它等待“默认”完成该过程。
除此之外,命名一个与模块同名的变量(我说的是tempfile)是一个坏的想法。我建议你把它改成tmpfile并查看NamedTemporaryFile,因为它比你现在正在做的更安全。