我大约一年前为客户建立了一个Django应用程序。他现在已将申请转售给一些超级秘密政府机构,他们甚至不会告诉我这个名字。
部分应用程序使用python库xhtml2pdf(pisa)动态生成PDF文件。政府不喜欢这个图书馆,他们不会告诉我为什么,他们说我必须使用HTMLDOC来生成pdf。
关于这个库的文档不多,但是通过阅读PHP示例,看起来你可以通过shell与它进行通信,因此它应该与Python一起使用。但是,我很难将HTML传递给HTMLDOC。看起来HTMLDOC只接受一个文件,但我真的需要将html作为字符串传递,因为它是动态生成的。 (或者将html字符串写入临时文件,然后将该临时文件传递给HTMLDOC)。
我认为StringIO会为此工作,但我收到了错误。这就是我所拥有的:
def render_to_pdf(template_src, context_dict):
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = StringIO.StringIO(html.encode("utf-8"))
os.putenv("HTMLDOC_NOCGI", "1")
#this line throws "[Errno 2] No such file or directory"
htmldoc = subprocess.Popen("htmldoc -t pdf --quiet '%s'" % result, stdout=subprocess.PIPE).communicate()
pdf = htmldoc[0]
result.close()
return HttpResponse(pdf, mimetype='application/pdf')
任何想法,提示或帮助都会非常感激。
感谢。
更新
堆栈追踪:
Environment:
Request Method: GET
Request URL: (redacted)
Django Version: 1.3 alpha 1 SVN-14921
Python Version: 2.6.5
Installed Applications:
['django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'application']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware')
Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/auth/decorators.py" in _wrapped_view
23. return view_func(request, *args, **kwargs)
File "/home/ascgov/application/views/pdf.py" in application_pdf
90. 'user':owner})
File "/home/ascgov/application/views/pdf.py" in render_to_pdf
53. htmldoc = subprocess.Popen("/usr/bin/htmldoc -t pdf --quiet '%s'" % result, stdout=subprocess.PIPE).communicate()
File "/usr/lib/python2.6/subprocess.py" in __init__
633. errread, errwrite)
File "/usr/lib/python2.6/subprocess.py" in _execute_child
1139. raise child_exception
Exception Type: OSError at /pdf/application/feed-filtr/
Exception Value: [Errno 2] No such file or directory
答案 0 :(得分:3)
首先,subprocess.Popen
的第一个arg通常应该是一个列表(除非你也传递shell=True
)。 No such file or directory
几乎可以肯定是由于系统上没有名为"htmldoc -t pdf --quiet '...
的文件(它试图找到并运行以整个字符串值命名的程序)。
其次,如果你在stdin上给htmldoc一些html,它会在stdout上吐出一个pdf,从而避免需要一个临时文件。
尝试一下(未经测试):
htmldoc = subprocess.Popen(
['/usr/bin/htmldoc', '-t', 'pdf', '--webpage', '-'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
stdout, stderr = htmldoc.communicate(html)
注意:将/usr/bin/htmldoc
替换为系统上htmldoc的真实路径。
htmldoc程序的-
参数告诉它从stdin读取。您将html字符串值(html
)传递给htmldoc的stdin
作为htmldoc.communicate
调用的参数。生成的pdf输出应该在stdout
中以及stderr
中的任何其他消息或统计信息中提供。
编辑:文档确实看起来有点不稳定,但有很多内容。您可以通过html in one page或pdf版本或man page获得更好的运气。
另外,请务必将字符串或类似字符串传递给htmldoc进程的stdin。直接传递StringIO对象,就像我之前的代码片段所暗示的那样,不起作用。
答案 1 :(得分:0)
Blergh。这是一个多么可怕的要求,也是一个可怕的计划。
似乎没有办法将内容转换为命令行选项。但它似乎确实接受了一个URL。因此,可以想象,您可以传递引用同一服务器上的视图的构造URL,并在第二个视图中输出您呈现的模板,然后由第一个视图中运行的HTMLDOC拾取。请注意,这不适用于开发服务器,因为它是单线程的,因此视图将永远等待彼此。