=========================== 通过 Django 输出 pdf =========================== 多亏有了优秀的开源库 ReportLab_ , Django 才可以通过 view 如此轻松的输出动态 pdf. .. _ReportLab: http://www.reportlab.org/rl_toolkit.html 安装 ReportLab ================= 从 http://www.reportlab.org/downloads.html下载然后安装 ReportLab . `user guide`_ (一个 pdf 文件) 会告诉你如何安装它. 在你的 Python 解释器中通过导入该模块检验它是否安装成功:: >>> import reportlab 如果上面这个命令没有引发任何错误,恭喜,你安装成功了! .. _user guide: http://www.reportlab.org/rsrc/userguide.pdf Write your view =============== Django 动态生成 pdf 的关键在于: ReportLab API 是一个类文件对象, 而 Django 的 ``HttpResponse`` 也是一个类文件对象. .. admonition:: Note 要了解 ``HttpResponse`` 对象更多,参阅 `Request and response objects`_. .. _Request and response objects: http://www.djangoproject.com/documentation/request_response/ 这里有一个 "Hello World" 简单例子:: from reportlab.pdfgen import canvas from django.http import HttpResponse def some_view(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(mimetype='application/pdf') response['Content-Disposition'] = 'attachment; filename=somefilename.pdf' # Create the PDF object, using the response object as its "file." p = canvas.Canvas(response) # Draw things on the PDF. Here's where the PDF generation happens. # See the ReportLab documentation for the full list of functionality. p.drawString(100, 100, "Hello world.") # Close the PDF object cleanly, and we're done. p.showPage() p.save() return response The code and comments should be self-explanatory, but a few things deserve a mention: * response 得到一个特殊的 mimetype, ``application/pdf``. 通过它告诉浏览器这个文档是一个 PDF 文件,而不是 HTML. 如果你漏掉了这一句, 浏览器可能就会按照 HTML 来解释输出, 这很可能造成输出紊乱. * response 得到一个附加的 ``Content-Disposition`` header, 该 header 包含 pdf 文件的名字. 文件名可以随便起, 它将用于浏览器的 "Save as..."对话框. * 在这个例子里 ``Content-Disposition`` header 内容由 ``'attachment; '`` 开头, 这将强制浏览器弹出一个对话框来提示/确认如何处理该文档.(即使本机安装了pdf阅读器). 如果你省掉了 ``'attachment;'``, 浏览器会使用被配置的 PDF 程序/插件来处理该文档. 那样子的话代码就象下面:: response['Content-Disposition'] = 'filename=somefilename.pdf' * 使用 ReportLab API 很容易: 将 ``response`` 作为 ``canvas.Canvas`` 的第一个参数就可以了. ``Canvas`` 类要求一个类文件对象, 而 ``HttpResponse`` 对象则正合适. * 注意所有后续的 PDF-generation 方法由 pdf 对象调用 (本例中是 ``p``) -- 而不是由 ``response`` 调用. * 最后,别忘了调用pdf对象的 ``showPage()`` 和 ``save()`` 方法 . Complex PDFs ============ If you're creating a complex PDF document with ReportLab, consider using the cStringIO_ library as a temporary holding place for your PDF file. The cStringIO library provides a file-like object interface that is particularly efficient. Here's the above "Hello World" example rewritten to use ``cStringIO``:: from cStringIO import StringIO from reportlab.pdfgen import canvas from django.utils.httpwrappers import HttpResponse def some_view(request): # Create the HttpResponse object with the appropriate PDF headers. response = HttpResponse(mimetype='application/pdf') response['Content-Disposition'] = 'attachment; filename=somefilename.pdf' buffer = StringIO() # Create the PDF object, using the StringIO object as its "file." p = canvas.Canvas(buffer) # Draw things on the PDF. Here's where the PDF generation happens. # See the ReportLab documentation for the full list of functionality. p.drawString(100, 100, "Hello world.") # Close the PDF object cleanly. p.showPage() p.save() # Get the value of the StringIO buffer and write it to the response. pdf = buffer.getvalue() buffer.close() response.write(pdf) return response .. _cStringIO: http://www.python.org/doc/current/lib/module-cStringIO.html Further resources ================= * PDFlib_ is another PDF-generation library that has Python bindings. To use it with Django, just use the same concepts explained in this article. * HTMLdoc_ is a command-line script that can convert HTML to PDF. It doesn't have a Python interface, but you can escape out to the shell using ``system`` or ``popen`` and retrieve the output in Python. * `forge_fdf in Python`_ is a library that fills in PDF forms. .. _PDFlib: http://www.pdflib.org/ .. _HTMLdoc: http://www.htmldoc.org/ .. _forge_fdf in Python: http://www.accesspdf.com/article.php/20050421092951834