python
  • django
  • pdf
  • popen
  • wkhtmltopdf
  • 2011-03-24 43 views 1 likes 
    1

    我在问一个与this one非常类似的问题。我在Django的Ubuntu服务器上使用wkhtmltopdf创建pdf。在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 = ...行。

    我也试着在popen = ...行添加.communicate(),但我似乎无法找到这种方式的PDF输出。我应该补充一点,在命令行中输入command_args行创建pdf就好了。任何人都可以将我指向正确的方向吗?

    +0

    当你手动运行此命令,是将其输出到控制台?还是仅限于gettempdir()+“/ results.pdf”文件? – 2011-03-24 19:24:25

    +0

    它输出到results.pdf文件,正确格式化和一切。 – buken 2011-03-24 19:32:44

    回答

    2

    你的第一个版本因为python不知道wkhtmltopdf的位置而失败。 Python不会检查你的路径。你的第二个版本将命令传递给一个处理这个问题的shell。你通过传递一个shell = True参数来达到同样的效果。

    第二个问题(正如其他人已经注意到的)是,当你不应该的时候调用stdout()。

    第三个问题是您的wkhtmltopdf命令错误。你正在做的:

    相反,你应该通过

    wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl - 
    

    这样wkhtmltopdf将输出写入到标准输出,你可以阅读。如果你传递另一个 - 作为源代码,你可以通过标准输入发送html。

    +0

    感谢您的快速回复。这几乎是python文件I/O的崩溃过程。我最终将输出直接传递到标准输出并绕过任何临时文件以避免安全事故。 – buken 2011-03-24 20:31:52

    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()函数时,您不必担心它,因为它会通过“default”等待进程完成。

    除此之外,命名与模块名称相同的变量(我正在谈论tempfile)是一个不好的想法。我建议您将其更改为tmpfile并检出NamedTemporaryFile s,因为它比现在更安全。

    +0

    不幸的是,这个调用在Python 2.7中是新的,我正在运行2.6。如果一切都失败,我可能会尝试升级。 – buken 2011-03-24 19:18:20

    +0

    感谢您的提示。我已经改变了tempfile变量的名字,并摆脱了terminate()。然而,尽管我看到服务器上正确的pdf文件,但我仍然收到一个空白的pdf文件。 – buken 2011-03-24 19:28:05

    +0

    如果这仍然不起作用,则可能需要在pdf_contents = process.stdout.read()之前添加process.wait()。希望能帮助到你。 – brahle 2011-03-24 19:36:23

    1

    你得到的原因'file' object is not callable是因为一旦你有你的popen对象,stdout是一个文件句柄,而不是一个方法。不要叫,只需要使用它:

    popen = Popen(command_args, stdout=PIPE, stderr=PIPE) 
    pdf_contents = popen.stdout.read() 
    
    +0

    非常感谢。但现在,而不是错误,我回来了一个空白的pdf文件(0字节)。我可以看到坐在服务器上的正确的pdf。任何想法为什么“sh”,“-c”参数摆脱“没有这样的文件或目录”错误? – buken 2011-03-24 19:20:28

    3

    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') 
    
    1

    我意识到这不使用wkhtmltopdf,但我觉得这是更清洁。

    看看https://docs.djangoproject.com/en/dev/howto/outputting-pdf/

    相关问题