在Django中返回PDF响应
我在问一个和这个问题非常相似的问题。我正在使用wkhtmltopdf在Ubuntu服务器上通过Django创建一个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 =...这一行,我又遇到了“'file'对象不可调用”的错误。
我还尝试在popen =...这一行添加了.communicate(),但我似乎找不到PDF的输出。我应该补充一下,直接在命令行输入command_args这一行可以正常生成PDF。有人能给我指个方向吗?
4 个回答
你看到的错误信息 'file' object is not callable
是因为当你创建了一个 popen
对象后,stdout
其实是一个文件句柄,而不是一个可以调用的方法。你不需要去调用它,只需要直接使用它就可以了:
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout.read()
wkhtmltopdf
没有把 PDF 的内容输出给 Popen
来读取。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')
你的第一个版本失败了,因为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内容。