0

約 1 年前にクライアント用の Django アプリケーションを構築しました。彼は今、名前さえ教えてくれない極秘の政府機関にアプリケーションを転売しました。

アプリケーションの一部は、Python ライブラリ xhtml2pdf (pisa) を使用して PDF ファイルを動的に生成します。政府はこのライブラリを気に入らず、理由を教えてくれません。pdf の生成にはHTMLDOCを使用する必要があるとのことです。

このライブラリに関するドキュメントはあまりありませんが、PHP の例を読むと、シェル経由で通信できるように見えるので、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
4

2 に答える 2

3

まず、subprocess.Popenの最初の引数は通常、リストでなければなりません ( も渡さない限りshell=True)。これNo such file or directoryはほぼ確実"htmldoc -t pdf --quiet '...に、システム上に名前が付けられたファイルが存在しないことが原因です (文字列値全体で名前が付けられたプログラムを見つけて実行しようとしています)。

次に、htmldoc の stdin に 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 に渡します。結果の pdf 出力は で利用でき、その他のメッセージまたは統計情報は で利用できます。stdinhtmldoc.communicatestdoutstderr

編集:ドキュメントは少し不安定に見えますが、かなりの量があります。1 ページの htmlpdfバージョン、またはman ページの方がうまくいくかもしれません。

また、必ず文字列などを htmldoc プロセスの stdin に渡してください。前のコード スニペットで示したように、StringIO オブジェクトを直接渡すことはできません。

于 2012-01-16T22:19:24.243 に答える
0

ブレル。なんという恐ろしい要件、そして恐ろしいプログラムでしょう。

コンテンツをコマンドライン オプションとして変換する方法はないようです。ただし、URL を受け入れるようです。したがって、おそらく、同じサーバー上のビューを参照する構築された URL を渡し、その 2 番目のビューでレンダリングされたテンプレートを出力し、それが最初のビューから実行されている HTMLDOC によって取得される可能性があります。シングルスレッドであるため、これは開発サーバーでは機能しないことに注意してください。そのため、ビューは互いに永遠に待機します。

于 2012-01-16T22:07:49.183 に答える