{"title":"How to create PDF files","version":"4.1","locale":"zh-hans","docname":"howto/outputting-pdf","url":"/zh-hans/4.1/howto/outputting-pdf/","canonical":"https://djangodocs.dev/zh-hans/4.1/howto/outputting-pdf/","summary":"本文介绍如何用 Django 的视图动态输出 PDF 文件。该功能由绝佳的开源 ReportLab Python PDF 库提供。 动态生成 PDF 文件的优点是你可以为不同的目的创建不同的自定义 PDF——例如，为不同的用户或内容的不同片段生成 PDF。 例如， kusports.com 用 Django…","html":"<h1>How to create PDF files<a class=\"heading-anchor\" href=\"#how-to-create-pdf-files\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>本文介绍如何用 Django 的视图动态输出 PDF 文件。该功能由绝佳的开源 <a class=\"reference external\" href=\"https://www.reportlab.com/opensource/\">ReportLab</a> Python  PDF 库提供。</p>\n<p>动态生成 PDF 文件的优点是你可以为不同的目的创建不同的自定义 PDF——例如，为不同的用户或内容的不同片段生成 PDF。</p>\n<p>例如，<a class=\"reference external\" href=\"http://www2.kusports.com/\">kusports.com</a> 用 Django 将自定义的，打印友好的 NCAA 锦标赛树状图生成 PDF 文件，发放给参加三月疯狂竞赛的人。</p>\n<section id=\"install-reportlab\">\n<h2>安装 ReportLab<a class=\"heading-anchor\" href=\"#install-reportlab\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>ReportLab 库可从 <a class=\"reference external\" href=\"https://www.reportlab.com/docs/reportlab-userguide.pdf\">PyPI</a> 获取。也可以下载 <a class=\"reference external\" href=\"https://pypi.org/project/reportlab/\">用户指南</a> （一份 PDF 文件，这不是巧合）。你可以用 <code class=\"docutils literal notranslate\"><span class=\"pre\">pip</span></code> 安装 ReportLab：</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-0-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>python<span class=\"w\"> </span>-m<span class=\"w\"> </span>pip<span class=\"w\"> </span>install<span class=\"w\"> </span>reportlab\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-0-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py -m pip install reportlab\n</code></pre></div></div></div>\n<p>在 Python 交互解释器中导入它，测试你的安装是否成功:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">reportlab</span>\n</code></pre></div>\n<p>若该命令未抛出任何错误，安装成功。</p>\n</section>\n<section id=\"write-your-view\">\n<h2>编写视图<a class=\"heading-anchor\" href=\"#write-your-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>利用 Django 动态生成 PDF 的关键是 ReportLab API 作用于类文件对象，而 Django 的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.FileResponse\" title=\"django.http.FileResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">FileResponse</span></code></a> 对象接收类文件对象。</p>\n<p>这有个 &quot;Hello World&quot; 示例:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">io</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">FileResponse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">reportlab.pdfgen</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">canvas</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">some_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Create a file-like buffer to receive PDF data.</span>\n    <span class=\"n\">buffer</span> <span class=\"o\">=</span> <span class=\"n\">io</span><span class=\"o\">.</span><span class=\"n\">BytesIO</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># Create the PDF object, using the buffer as its &quot;file.&quot;</span>\n    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">canvas</span><span class=\"o\">.</span><span class=\"n\">Canvas</span><span class=\"p\">(</span><span class=\"n\">buffer</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Draw things on the PDF. Here&#39;s where the PDF generation happens.</span>\n    <span class=\"c1\"># See the ReportLab documentation for the full list of functionality.</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">drawString</span><span class=\"p\">(</span><span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Hello world.&quot;</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Close the PDF object cleanly, and we&#39;re done.</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">showPage</span><span class=\"p\">()</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># FileResponse sets the Content-Disposition header so that browsers</span>\n    <span class=\"c1\"># present the option to save the file.</span>\n    <span class=\"n\">buffer</span><span class=\"o\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">FileResponse</span><span class=\"p\">(</span><span class=\"n\">buffer</span><span class=\"p\">,</span> <span class=\"n\">as_attachment</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"o\">=</span><span class=\"s1\">&#39;hello.pdf&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>代码和注释应该是不言自明的，但是有几件事值得提一下：</p>\n<ul class=\"simple\">\n<li><p>响应会自动基于文件扩展名将 MIME 类型设置为应用程序 <em class=\"mimetype\">application/pdf</em>。这告诉浏览器该文档是个 PDF 文件，而不是 HTML 文件或普通的应用程序 <em class=\"mimetype\">application/octet-stream</em> 二进制内容。</p></li>\n<li><p>When <code class=\"docutils literal notranslate\"><span class=\"pre\">as_attachment=True</span></code> is passed to <code class=\"docutils literal notranslate\"><span class=\"pre\">FileResponse</span></code>, it sets the\nappropriate <code class=\"docutils literal notranslate\"><span class=\"pre\">Content-Disposition</span></code> header and that tells web browsers to\npop-up a dialog box prompting/confirming how to handle the document even if a\ndefault is set on the machine. If the <code class=\"docutils literal notranslate\"><span class=\"pre\">as_attachment</span></code> parameter is omitted,\nbrowsers will handle the PDF using whatever program/plugin they've been\nconfigured to use for PDFs.</p></li>\n<li><p>你也可以提供可选参数 <code class=\"docutils literal notranslate\"><span class=\"pre\">filename</span></code>。浏览器的“另存为…”对话框会用到它。</p></li>\n<li><p>你可以作为第一个参数传递给 <code class=\"docutils literal notranslate\"><span class=\"pre\">canvas.Canvas</span></code> 的缓冲区也能传递给类 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.FileResponse\" title=\"django.http.FileResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">FileResponse</span></code></a> 类来使用 ReportLab API。</p></li>\n<li><p>注意，所有后续生成 PDF 的方法都是在 PDF 对象上调用的（本例中是 <code class=\"docutils literal notranslate\"><span class=\"pre\">p</span></code>）——而不是在 <code class=\"docutils literal notranslate\"><span class=\"pre\">buffer</span></code> 上调用。</p></li>\n<li><p>最后，牢记在 PDF 文件上调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">showPage()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">save()</span></code>。</p></li>\n</ul>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>ReportLab 不是线程安全的。某些用户已经报告了一些奇怪的 issue，在创建用于生成 PDF 的 Django 视图时，这些视图被多个用户同时访问会出现问题。</p>\n</aside>\n</section>\n<section id=\"other-formats\">\n<h2>其它格式<a class=\"heading-anchor\" href=\"#other-formats\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>注意，这些例子中没有任何 PDF 特有的数据——只有使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">reportlab</span></code> 的部分。你可以用类似的技巧生成任意格式，只要你能找到对应的 Python 库。也请看看 <a class=\"reference internal\" href=\"/zh-hans/4.1/howto/outputting-csv/\"><span class=\"doc\">How to create CSV output</span></a>，看看另一个例子中，如何用一些技巧输出文本内容。</p>\n<aside class=\"admonition admonition-seealso\">\n<p class=\"admonition-title\">See also</p>\n<p>Django 包提供了一个 <a class=\"reference external\" href=\"https://djangopackages.org/grids/g/pdf/\">包的比较</a> 有助于用 Django 生成 PDF 文件。</p>\n</aside>\n</section>","rootId":"how-to-create-pdf-files","toc":[{"title":"安装 ReportLab","anchor":"install-reportlab","children":[]},{"title":"编写视图","anchor":"write-your-view","children":[]},{"title":"其它格式","anchor":"other-formats","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"操作指南","url":"/zh-hans/4.1/howto/"}],"prev":{"docname":"howto/outputting-csv","title":"How to create CSV output","url":"/zh-hans/4.1/howto/outputting-csv/"},"next":{"docname":"howto/overriding-templates","title":"How to override templates","url":"/zh-hans/4.1/howto/overriding-templates/"},"formats":{"html":"/zh-hans/4.1/howto/outputting-pdf/","markdown":"/zh-hans/4.1/howto/outputting-pdf.md","json":"/zh-hans/4.1/howto/outputting-pdf.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/howto/outputting-pdf.txt","official":"https://docs.djangoproject.com/zh-hans/4.1/howto/outputting-pdf/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}