{"title":"如何输出 CSV","version":"5.0","locale":"zh-hans","docname":"howto/outputting-csv","url":"/zh-hans/5.0/howto/outputting-csv/","canonical":"https://djangodocs.dev/zh-hans/5.0/howto/outputting-csv/","summary":"本文介绍如何用 Django 的视图动态输出 CSV (Comma Separated Values)。要达到目的，你可以使用 Python 的 CSV 库或 Django 的模板系统。 使用 Python 的 CSV 库 Link to this heading # Python 有用一个 CSV 库 csv 。它配合…","html":"<h1>如何输出 CSV<a class=\"heading-anchor\" href=\"#how-to-create-csv-output\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>本文介绍如何用 Django 的视图动态输出 CSV (Comma Separated Values)。要达到目的，你可以使用 Python 的 CSV 库或 Django 的模板系统。</p>\n<section id=\"using-the-python-csv-library\">\n<h2>使用 Python 的 CSV 库<a class=\"heading-anchor\" href=\"#using-the-python-csv-library\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Python 有用一个 CSV 库 <a class=\"reference external\" href=\"https://docs.python.org/3/library/csv.html#module-csv\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">csv</span></code></a>。它配合 Django 使用的关键是 <a class=\"reference external\" href=\"https://docs.python.org/3/library/csv.html#module-csv\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">csv</span></code></a> 模块的 CSV 创建行为作用于类文件对象，而 Django 的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象也是类文件对象。</p>\n<p>这有个例子:</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\">csv</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\">HttpResponse</span>\n\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 the HttpResponse object with the appropriate CSV header.</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span>\n        <span class=\"n\">content_type</span><span class=\"o\">=</span><span class=\"s2\">&quot;text/csv&quot;</span><span class=\"p\">,</span>\n        <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;Content-Disposition&quot;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;attachment; filename=&quot;somefilename.csv&quot;&#39;</span><span class=\"p\">},</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">csv</span><span class=\"o\">.</span><span class=\"n\">writer</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">)</span>\n    <span class=\"n\">writer</span><span class=\"o\">.</span><span class=\"n\">writerow</span><span class=\"p\">([</span><span class=\"s2\">&quot;First row&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Foo&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Bar&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Baz&quot;</span><span class=\"p\">])</span>\n    <span class=\"n\">writer</span><span class=\"o\">.</span><span class=\"n\">writerow</span><span class=\"p\">([</span><span class=\"s2\">&quot;Second row&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;A&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;B&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;C&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&quot;Testing&quot;&#39;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Here&#39;s a quote&quot;</span><span class=\"p\">])</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n<p>代码和注释应该是不言自明的，但是有几件事值得提一下：</p>\n<ul class=\"simple\">\n<li><p>响应指定了特殊的 MIME 类型 <em class=\"mimetype\">text/csv</em>。这告诉浏览器该文档是一个 CSV 文件，而不是一个 HTML 文件。如果你没这么干，浏览器可能会将输出视作 HTML，这会在浏览器窗口展示丑陋的，恐怖的官样文章。</p></li>\n<li><p>相应还包括一个额外的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Content-Disposition</span></code> 头，其中包含了 CSV 文件的名称。文件名是任意的；随便你怎么叫。它会被浏览器在 &quot;保存为……&quot; 对话框中用到。</p></li>\n<li><p>你需将 <code class=\"docutils literal notranslate\"><span class=\"pre\">response</span></code> 作为第一个参数传给 <code class=\"docutils literal notranslate\"><span class=\"pre\">csv.writer</span></code> 来接入生成 CSV API 。 <code class=\"docutils literal notranslate\"><span class=\"pre\">csv.writer</span></code> 函数期望一个类文件对象，而 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> 对象满足该要求。</p></li>\n<li><p>要按行输出 CSV 文件，调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">writer.writerrow</span></code>，传入一个 <a class=\"reference external\" href=\"https://docs.python.org/3/glossary.html#term-iterable\" title=\"(in Python v3.14)\"><span class=\"xref std std-term\">iterable</span></a> 参数。</p></li>\n<li><p>CSV 模块为你处理了引号，所以你无需担心包含引号或逗号的字符串的转义问题。你需要为 <code class=\"docutils literal notranslate\"><span class=\"pre\">writerow()</span></code> 传入原始字符串，它为你处理好一切。</p></li>\n</ul>\n<section id=\"streaming-large-csv-files\">\n<span id=\"streaming-csv-files\"></span><h3>输出超大 CSV 文件<a class=\"heading-anchor\" href=\"#streaming-large-csv-files\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当处理生成很多回复的视图时，你可能要考虑使用 Django 的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.StreamingHttpResponse\" title=\"django.http.StreamingHttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">StreamingHttpResponse</span></code></a> 作为替代。例如，要进行耗时的输出文件流的操作，你可以避免负载均衡器在服务器输出耗时相应时，可能由于超时抛弃改连接。</p>\n<p>在本例中，我们充分利用 Python 的生成器，高效地处理大型 CSV 文件的装配和输出任务:</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\">csv</span>\n\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\">StreamingHttpResponse</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Echo</span><span class=\"p\">:</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;An object that implements just the write method of the file-like</span>\n<span class=\"sd\">    interface.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">write</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Write the value by returning it, instead of storing in a buffer.&quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">value</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">some_streaming_csv_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;A view that streams a large CSV file.&quot;&quot;&quot;</span>\n    <span class=\"c1\"># Generate a sequence of rows. The range is based on the maximum number of</span>\n    <span class=\"c1\"># rows that can be handled by a single sheet in most spreadsheet</span>\n    <span class=\"c1\"># applications.</span>\n    <span class=\"n\">rows</span> <span class=\"o\">=</span> <span class=\"p\">([</span><span class=\"s2\">&quot;Row </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">),</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">idx</span><span class=\"p\">)]</span> <span class=\"k\">for</span> <span class=\"n\">idx</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">65536</span><span class=\"p\">))</span>\n    <span class=\"n\">pseudo_buffer</span> <span class=\"o\">=</span> <span class=\"n\">Echo</span><span class=\"p\">()</span>\n    <span class=\"n\">writer</span> <span class=\"o\">=</span> <span class=\"n\">csv</span><span class=\"o\">.</span><span class=\"n\">writer</span><span class=\"p\">(</span><span class=\"n\">pseudo_buffer</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">StreamingHttpResponse</span><span class=\"p\">(</span>\n        <span class=\"p\">(</span><span class=\"n\">writer</span><span class=\"o\">.</span><span class=\"n\">writerow</span><span class=\"p\">(</span><span class=\"n\">row</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">row</span> <span class=\"ow\">in</span> <span class=\"n\">rows</span><span class=\"p\">),</span>\n        <span class=\"n\">content_type</span><span class=\"o\">=</span><span class=\"s2\">&quot;text/csv&quot;</span><span class=\"p\">,</span>\n        <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;Content-Disposition&quot;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;attachment; filename=&quot;somefilename.csv&quot;&#39;</span><span class=\"p\">},</span>\n    <span class=\"p\">)</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"using-the-template-system\">\n<h2>使用模板系统<a class=\"heading-anchor\" href=\"#using-the-template-system\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>或者，你也能用 <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/templates/\"><span class=\"doc\">Djano 模板系统</span></a> 生成 CSV。这比使用方便的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/csv.html#module-csv\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">csv</span></code></a> 模块级别低点，但是，解决方案就在这，你可以选。</p>\n<p>办法就是将项目列表传给模板，让模板在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">for</span></code></a> 循环中输出逗号。</p>\n<p>以下例子输出与前文一样的 CSV 文件:</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\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.template</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">loader</span>\n\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 the HttpResponse object with the appropriate CSV header.</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span>\n        <span class=\"n\">content_type</span><span class=\"o\">=</span><span class=\"s2\">&quot;text/csv&quot;</span><span class=\"p\">,</span>\n        <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;Content-Disposition&quot;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;attachment; filename=&quot;somefilename.csv&quot;&#39;</span><span class=\"p\">},</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"c1\"># The data is hard-coded here, but you could load it from a database or</span>\n    <span class=\"c1\"># some other source.</span>\n    <span class=\"n\">csv_data</span> <span class=\"o\">=</span> <span class=\"p\">(</span>\n        <span class=\"p\">(</span><span class=\"s2\">&quot;First row&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Foo&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Bar&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Baz&quot;</span><span class=\"p\">),</span>\n        <span class=\"p\">(</span><span class=\"s2\">&quot;Second row&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;A&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;B&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;C&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&quot;Testing&quot;&#39;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Here&#39;s a quote&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">loader</span><span class=\"o\">.</span><span class=\"n\">get_template</span><span class=\"p\">(</span><span class=\"s2\">&quot;my_template_name.txt&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;data&quot;</span><span class=\"p\">:</span> <span class=\"n\">csv_data</span><span class=\"p\">}</span>\n    <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">c</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n<p>本例与前例唯一的不同是本例使用模板加载，而不是 CSV 模块。剩下的代码都一样，例如  <code class=\"docutils literal notranslate\"><span class=\"pre\">content_type='text/csv'</span></code>。</p>\n<p>然后，用模板代码创建模板 <code class=\"docutils literal notranslate\"><span class=\"pre\">my_template_name.txt</span></code>。</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</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=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">row</span> <span class=\"k\">in</span> <span class=\"nv\">data</span> <span class=\"cp\">%}</span>&quot;<span class=\"cp\">{{</span> <span class=\"nv\">row.0</span><span class=\"o\">|</span><span class=\"nf\">addslashes</span> <span class=\"cp\">}}</span>&quot;, &quot;<span class=\"cp\">{{</span> <span class=\"nv\">row.1</span><span class=\"o\">|</span><span class=\"nf\">addslashes</span> <span class=\"cp\">}}</span>&quot;, &quot;<span class=\"cp\">{{</span> <span class=\"nv\">row.2</span><span class=\"o\">|</span><span class=\"nf\">addslashes</span> <span class=\"cp\">}}</span>&quot;, &quot;<span class=\"cp\">{{</span> <span class=\"nv\">row.3</span><span class=\"o\">|</span><span class=\"nf\">addslashes</span> <span class=\"cp\">}}</span>&quot;, &quot;<span class=\"cp\">{{</span> <span class=\"nv\">row.4</span><span class=\"o\">|</span><span class=\"nf\">addslashes</span> <span class=\"cp\">}}</span>&quot;\n<span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>这个简短的模板遍历所给的数据，并为每行生成一个 CSV 行。它利用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/templates/builtins/#std-templatefilter-addslashes\"><code class=\"xref std std-tfilter docutils literal notranslate\"><span class=\"pre\">addslashes</span></code></a> 模板过滤器确保引号不会引发任何问题。</p>\n</section>\n<section id=\"other-text-based-formats\">\n<h2>其它文本格式<a class=\"heading-anchor\" href=\"#other-text-based-formats\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>注意，这里并没有太多特定于 CSV 的内容——仅是特定的输出格式。你可以使用其中任意一种输出你能想到文本内容。你也能用类似的技术生成任意二进制数据；参考 <a class=\"reference internal\" href=\"/zh-hans/5.0/howto/outputting-pdf/\"><span class=\"doc\">如何创建 PDF 文件</span></a> 的例子。</p>\n</section>","rootId":"how-to-create-csv-output","toc":[{"title":"使用 Python 的 CSV 库","anchor":"using-the-python-csv-library","children":[{"title":"输出超大 CSV 文件","anchor":"streaming-large-csv-files","children":[]}]},{"title":"使用模板系统","anchor":"using-the-template-system","children":[]},{"title":"其它文本格式","anchor":"other-text-based-formats","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"操作指南","url":"/zh-hans/5.0/howto/"}],"prev":{"docname":"howto/logging","title":"如何配置和使用日志","url":"/zh-hans/5.0/howto/logging/"},"next":{"docname":"howto/outputting-pdf","title":"如何创建 PDF 文件","url":"/zh-hans/5.0/howto/outputting-pdf/"},"formats":{"html":"/zh-hans/5.0/howto/outputting-csv/","markdown":"/zh-hans/5.0/howto/outputting-csv.md","json":"/zh-hans/5.0/howto/outputting-csv.json"},"source":"https://github.com/django/django/blob/stable/5.0.x/docs/howto/outputting-csv.txt","official":"https://docs.djangoproject.com/zh-hans/5.0/howto/outputting-csv/","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"]}