“Django/docs/2.2.x/howto/outputting-csv”的版本间差异

来自菜鸟教程
Django/docs/2.2.x/howto/outputting-csv
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:使用 Django 输出 CSV — Django 文档}}
 
<div id="outputting-csv-with-django" class="section">
 
<div id="outputting-csv-with-django" class="section">
  
 
= 利用 Django 输出 CSV =
 
= 利用 Django 输出 CSV =
  
本文介绍如何用 Django 的视图动态输出 CSV (Comma Separated Values)。要达到目的,你可以使用 Python CSV 库或 Django 的模板系统。
+
本文档解释了如何使用 Django 视图动态输出 CSV(逗号分隔值)。 为此,您可以使用 Python CSV 库或 Django 模板系统。
  
 
<div id="using-the-python-csv-library" class="section">
 
<div id="using-the-python-csv-library" class="section">
第9行: 第10行:
 
== 使用 Python 的 CSV 库 ==
 
== 使用 Python 的 CSV 库 ==
  
Python 有用一个 CSV <code>csv</code>。它配合 Django 使用的关键是 <code>csv</code> 模块的 CSV 创建行为作用于类文件对象,而 Django 的 [[../../ref/request-response#django.http|<code>HttpResponse</code>]] 对象也是类文件对象。
+
Python 附带了一个 CSV 库,<code>csv</code>。 与 Django 一起使用的关键是 <code>csv</code> 模块的 CSV 创建功能作用于类文件对象,而 Django 的 [[../../ref/request-response#django.http|HttpResponse]] 对象是类文件对象。
  
这有个例子:
+
下面是一个例子:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第17行: 第18行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import csv
+
<syntaxhighlight lang="python">import csv
 
from django.http import HttpResponse
 
from django.http import HttpResponse
  
第23行: 第24行:
 
     # Create the HttpResponse object with the appropriate CSV header.
 
     # Create the HttpResponse object with the appropriate CSV header.
 
     response = HttpResponse(content_type='text/csv')
 
     response = HttpResponse(content_type='text/csv')
     response['Content-Disposition'] = 'attachment; filename=&quot;somefilename.csv&quot;'
+
     response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
  
 
     writer = csv.writer(response)
 
     writer = csv.writer(response)
 
     writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
 
     writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
     writer.writerow(['Second row', 'A', 'B', 'C', '&quot;Testing&quot;', &quot;Here's a quote&quot;])
+
     writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
  
     return response</pre>
+
     return response</syntaxhighlight>
  
 
</div>
 
</div>
第36行: 第37行:
 
代码和注释应该是不言自明的,但是有几件事值得提一下:
 
代码和注释应该是不言自明的,但是有几件事值得提一下:
  
* 响应指定了特殊的 MIME 类型 ''text/csv''。这告诉浏览器该文档是一个 CSV 文件,而不是一个 HTML 文件。如果你没这么干,浏览器可能会将输出视作 HTML,这会在浏览器窗口展示丑陋的,恐怖的官样文章。
+
* 响应获得一个特殊的 MIME 类型,''text/csv''。 这告诉浏览器该文档是一个 CSV 文件,而不是一个 HTML 文件。 如果你不这样做,浏览器可能会将输出解释为 HTML,这将导致浏览器窗口中出现丑陋、可怕的 gobbledygook。
* 相应还包括一个额外的 <code>Content-Disposition</code> 头,其中包含了 CSV 文件的名称。文件名是任意的;随便你怎么叫。它会被浏览器在 &quot;保存为……&quot; 对话框中用到。
+
* 响应获得一个额外的 <code>Content-Disposition</code> 标头,其中包含 CSV 文件的名称。 这个文件名是任意的; 随心所欲地称呼它。 浏览器将在“另存为...”对话框等中使用它。
* 接入生成 CSV API 非常简单:仅需将 <code>response</code> 作为第一个参数传给 <code>csv.writer</code>。 <code>csv.writer</code> 函数期望一个类文件对象,而 [[../../ref/request-response#django.http|<code>HttpResponse</code>]] 对象满足该要求。
+
* 连接到 CSV 生成 API 很容易:只需将 <code>response</code> 作为第一个参数传递给 <code>csv.writer</code>。 <code>csv.writer</code> 函数需要一个类似文件的对象,而 [[../../ref/request-response#django.http|HttpResponse]] 对象符合要求。
* 要按行输出 CSV 文件,调用 <code>writer.writerrow</code>,传入一个 <span class="xref std std-term">iterable</span> 参数。
+
* 对于 CSV 文件中的每一行,调用 <code>writer.writerow</code>,传递一个 <span class="xref std std-term">iterable</span>
* CSV 模块为你处理了引号,所以你无需担心包含引号或逗号的字符串的转义问题。只需为 <code>writerow()</code> 传入原始字符串,它为你处理好一切。
+
* CSV 模块会为您处理引号,因此您不必担心使用引号或逗号对字符串进行转义。 只需传递 <code>writerow()</code> 您的原始字符串,它就会做正确的事情。
  
 
<div id="streaming-large-csv-files" class="section">
 
<div id="streaming-large-csv-files" class="section">
第47行: 第48行:
 
=== 输出超大 CSV 文件 ===
 
=== 输出超大 CSV 文件 ===
  
当处理生成很多回复的视图时,你可能要考虑使用 Django 的 [[../../ref/request-response#django.http|<code>StreamingHttpResponse</code>]] 作为替代。例如,要进行耗时的输出文件流的操作,你可以避免负载均衡器在服务器输出耗时相应时,可能由于超时抛弃改连接。
+
在处理生成非常大响应的视图时,您可能需要考虑使用 Django 的 [[../../ref/request-response#django.http|StreamingHttpResponse]] 代替。 例如,通过流式传输需要很长时间生成的文件,您可以避免负载均衡器丢弃在服务器生成响应时可能会超时的连接。
  
在本例中,我们充分利用 Python 的生成器,高效地处理大型 CSV 文件的装配和输出任务:
+
在这个例子中,我们充分利用了 Python 生成器来高效处理大型 CSV 文件的组装和传输:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第55行: 第56行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import csv
+
<syntaxhighlight lang="python">import csv
  
 
from django.http import StreamingHttpResponse
 
from django.http import StreamingHttpResponse
  
 
class Echo:
 
class Echo:
     &quot;&quot;&quot;An object that implements just the write method of the file-like
+
     """An object that implements just the write method of the file-like
 
     interface.
 
     interface.
     &quot;&quot;&quot;
+
     """
 
     def write(self, value):
 
     def write(self, value):
         &quot;&quot;&quot;Write the value by returning it, instead of storing in a buffer.&quot;&quot;&quot;
+
         """Write the value by returning it, instead of storing in a buffer."""
 
         return value
 
         return value
  
 
def some_streaming_csv_view(request):
 
def some_streaming_csv_view(request):
     &quot;&quot;&quot;A view that streams a large CSV file.&quot;&quot;&quot;
+
     """A view that streams a large CSV file."""
 
     # Generate a sequence of rows. The range is based on the maximum number of
 
     # Generate a sequence of rows. The range is based on the maximum number of
 
     # rows that can be handled by a single sheet in most spreadsheet
 
     # rows that can be handled by a single sheet in most spreadsheet
 
     # applications.
 
     # applications.
     rows = ([&quot;Row {}&quot;.format(idx), str(idx)] for idx in range(65536))
+
     rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
 
     pseudo_buffer = Echo()
 
     pseudo_buffer = Echo()
 
     writer = csv.writer(pseudo_buffer)
 
     writer = csv.writer(pseudo_buffer)
 
     response = StreamingHttpResponse((writer.writerow(row) for row in rows),
 
     response = StreamingHttpResponse((writer.writerow(row) for row in rows),
                                     content_type=&quot;text/csv&quot;)
+
                                     content_type="text/csv")
     response['Content-Disposition'] = 'attachment; filename=&quot;somefilename.csv&quot;'
+
     response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
     return response</pre>
+
     return response</syntaxhighlight>
  
 
</div>
 
</div>
第91行: 第92行:
 
== 使用模板系统 ==
 
== 使用模板系统 ==
  
或者,你也能用 [[../../topics/templates|<span class="doc">Djano 模板系统</span>]] 生成 CSV。这比使用方便的 <code>csv</code> 模块级别低点,但是,解决方案就在这,你可以选。
+
或者,您可以使用 [[../../topics/templates|Django 模板系统]] 生成 CSV。 这比使用方便的 Python <code>csv</code> 模块低级,但为了完整起见,这里提供了解决方案。
  
办法就是将项目列表传给模板,让模板在 [[../../ref/templates/builtins#std-templatetag-for|<code>for</code>]] 循环中输出逗号。
+
这里的想法是将项目列表传递给您的模板,并让模板在 [[#id1|:ttag:`for`]] 循环中输出逗号。
  
以下例子输出与前文一样的 CSV 文件:
+
这是一个示例,它生成与上述相同的 CSV 文件:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第101行: 第102行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.http import HttpResponse
+
<syntaxhighlight lang="python">from django.http import HttpResponse
 
from django.template import loader
 
from django.template import loader
  
第107行: 第108行:
 
     # Create the HttpResponse object with the appropriate CSV header.
 
     # Create the HttpResponse object with the appropriate CSV header.
 
     response = HttpResponse(content_type='text/csv')
 
     response = HttpResponse(content_type='text/csv')
     response['Content-Disposition'] = 'attachment; filename=&quot;somefilename.csv&quot;'
+
     response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
  
 
     # The data is hard-coded here, but you could load it from a database or
 
     # The data is hard-coded here, but you could load it from a database or
第113行: 第114行:
 
     csv_data = (
 
     csv_data = (
 
         ('First row', 'Foo', 'Bar', 'Baz'),
 
         ('First row', 'Foo', 'Bar', 'Baz'),
         ('Second row', 'A', 'B', 'C', '&quot;Testing&quot;', &quot;Here's a quote&quot;),
+
         ('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
 
     )
 
     )
  
第119行: 第120行:
 
     c = {'data': csv_data}
 
     c = {'data': csv_data}
 
     response.write(t.render(c))
 
     response.write(t.render(c))
     return response</pre>
+
     return response</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
本例与前例唯一的不同是本例使用模板加载,而不是 CSV 模块。剩下的代码都一样,例如 <code>content_type='text/csv'</code>
+
此示例与上一个示例之间的唯一区别在于,此示例使用模板加载而不是 CSV 模块。 其余代码 - 例如 <code>content_type='text/csv'</code> - 是相同的。
  
然后,用模板代码创建模板 <code>my_template_name.txt</code>
+
然后,使用以下模板代码创建模板 <code>my_template_name.txt</code>
  
 
<div class="highlight-html+django notranslate">
 
<div class="highlight-html+django notranslate">
第132行: 第133行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>{% for row in data %}&quot;{{ row.0|addslashes }}&quot;, &quot;{{ row.1|addslashes }}&quot;, &quot;{{ row.2|addslashes }}&quot;, &quot;{{ row.3|addslashes }}&quot;, &quot;{{ row.4|addslashes }}&quot;
+
<syntaxhighlight lang="html+django">{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}</pre>
+
{% endfor %}</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
本例非常基础。它仅仅遍历所给的数据,并为每行生成一个 CSV 行。它利用 [[../../ref/templates/builtins#std-templatefilter-addslashes|<code>addslashes</code>]] 模板过滤器确保引号不会引发任何问题。
+
这个模板非常基础。 它只是遍历给定的数据并为每一行显示一行 CSV。 它使用 [[#id3|:tfilter:`addslashes`]] 模板过滤器来确保引号没有任何问题。
  
  
第146行: 第147行:
 
== 其它文本格式 ==
 
== 其它文本格式 ==
  
注意,这里并没有太多特定于 CSV 的内容——仅是特定的输出格式。你可以使用其中任意一种输出你能想到文本内容。你也能用类似的技术生成任意二进制数据;参考 [[../outputting-pdf|<span class="doc">利用 Django 输出 PDF</span>]] 的例子。
+
请注意,这里没有特别针对 CSV 的内容——只是特定的输出格式。 您可以使用这些技术中的任何一种来输出您梦寐以求的任何基于文本的格式。 您也可以使用类似的技术来生成任意二进制数据; 有关示例,请参阅 [[../outputting-pdf|使用 Django]] 输出 PDF。
  
  
第152行: 第153行:
  
 
</div>
 
</div>
 +
<div class="clearer">
  
[[Category:Django 2.2.x 中文文档]]
+
 
 +
 
 +
</div>
 +
 
 +
[[Category:Django 2.2.x 文档]]

2021年10月31日 (日) 04:04的最新版本

利用 Django 输出 CSV

本文档解释了如何使用 Django 视图动态输出 CSV(逗号分隔值)。 为此,您可以使用 Python CSV 库或 Django 模板系统。

使用 Python 的 CSV 库

Python 附带了一个 CSV 库,csv。 与 Django 一起使用的关键是 csv 模块的 CSV 创建功能作用于类文件对象,而 Django 的 HttpResponse 对象是类文件对象。

下面是一个例子:

import csv
from django.http import HttpResponse

def some_view(request):
    # Create the HttpResponse object with the appropriate CSV header.
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'

    writer = csv.writer(response)
    writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
    writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])

    return response

代码和注释应该是不言自明的,但是有几件事值得提一下:

  • 响应获得一个特殊的 MIME 类型,text/csv。 这告诉浏览器该文档是一个 CSV 文件,而不是一个 HTML 文件。 如果你不这样做,浏览器可能会将输出解释为 HTML,这将导致浏览器窗口中出现丑陋、可怕的 gobbledygook。
  • 响应获得一个额外的 Content-Disposition 标头,其中包含 CSV 文件的名称。 这个文件名是任意的; 随心所欲地称呼它。 浏览器将在“另存为...”对话框等中使用它。
  • 连接到 CSV 生成 API 很容易:只需将 response 作为第一个参数传递给 csv.writercsv.writer 函数需要一个类似文件的对象,而 HttpResponse 对象符合要求。
  • 对于 CSV 文件中的每一行,调用 writer.writerow,传递一个 iterable
  • CSV 模块会为您处理引号,因此您不必担心使用引号或逗号对字符串进行转义。 只需传递 writerow() 您的原始字符串,它就会做正确的事情。

输出超大 CSV 文件

在处理生成非常大响应的视图时,您可能需要考虑使用 Django 的 StreamingHttpResponse 代替。 例如,通过流式传输需要很长时间生成的文件,您可以避免负载均衡器丢弃在服务器生成响应时可能会超时的连接。

在这个例子中,我们充分利用了 Python 生成器来高效处理大型 CSV 文件的组装和传输:

import csv

from django.http import StreamingHttpResponse

class Echo:
    """An object that implements just the write method of the file-like
    interface.
    """
    def write(self, value):
        """Write the value by returning it, instead of storing in a buffer."""
        return value

def some_streaming_csv_view(request):
    """A view that streams a large CSV file."""
    # Generate a sequence of rows. The range is based on the maximum number of
    # rows that can be handled by a single sheet in most spreadsheet
    # applications.
    rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
    pseudo_buffer = Echo()
    writer = csv.writer(pseudo_buffer)
    response = StreamingHttpResponse((writer.writerow(row) for row in rows),
                                     content_type="text/csv")
    response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
    return response

使用模板系统

或者,您可以使用 Django 模板系统 生成 CSV。 这比使用方便的 Python csv 模块低级,但为了完整起见,这里提供了解决方案。

这里的想法是将项目列表传递给您的模板,并让模板在 :ttag:`for` 循环中输出逗号。

这是一个示例,它生成与上述相同的 CSV 文件:

from django.http import HttpResponse
from django.template import loader

def some_view(request):
    # Create the HttpResponse object with the appropriate CSV header.
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'

    # The data is hard-coded here, but you could load it from a database or
    # some other source.
    csv_data = (
        ('First row', 'Foo', 'Bar', 'Baz'),
        ('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
    )

    t = loader.get_template('my_template_name.txt')
    c = {'data': csv_data}
    response.write(t.render(c))
    return response

此示例与上一个示例之间的唯一区别在于,此示例使用模板加载而不是 CSV 模块。 其余代码 - 例如 content_type='text/csv' - 是相同的。

然后,使用以下模板代码创建模板 my_template_name.txt

{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}

这个模板非常基础。 它只是遍历给定的数据并为每一行显示一行 CSV。 它使用 :tfilter:`addslashes` 模板过滤器来确保引号没有任何问题。


其它文本格式

请注意,这里没有特别针对 CSV 的内容——只是特定的输出格式。 您可以使用这些技术中的任何一种来输出您梦寐以求的任何基于文本的格式。 您也可以使用类似的技术来生成任意二进制数据; 有关示例,请参阅 使用 Django 输出 PDF。