“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(逗号分隔值)。 为此,您可以使用 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 | + | 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"> | ||
− | < | + | <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= | + | 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', ' | + | writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"]) |
− | return response</ | + | return response</syntaxhighlight> |
</div> | </div> | ||
第36行: | 第37行: | ||
代码和注释应该是不言自明的,但是有几件事值得提一下: | 代码和注释应该是不言自明的,但是有几件事值得提一下: | ||
− | * | + | * 响应获得一个特殊的 MIME 类型,''text/csv''。 这告诉浏览器该文档是一个 CSV 文件,而不是一个 HTML 文件。 如果你不这样做,浏览器可能会将输出解释为 HTML,这将导致浏览器窗口中出现丑陋、可怕的 gobbledygook。 |
− | * | + | * 响应获得一个额外的 <code>Content-Disposition</code> 标头,其中包含 CSV 文件的名称。 这个文件名是任意的; 随心所欲地称呼它。 浏览器将在“另存为...”对话框等中使用它。 |
− | * | + | * 连接到 CSV 生成 API 很容易:只需将 <code>response</code> 作为第一个参数传递给 <code>csv.writer</code>。 <code>csv.writer</code> 函数需要一个类似文件的对象,而 [[../../ref/request-response#django.http|HttpResponse]] 对象符合要求。 |
− | * | + | * 对于 CSV 文件中的每一行,调用 <code>writer.writerow</code>,传递一个 <span class="xref std std-term">iterable</span>。 |
− | * CSV | + | * 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|StreamingHttpResponse]] 代替。 例如,通过流式传输需要很长时间生成的文件,您可以避免负载均衡器丢弃在服务器生成响应时可能会超时的连接。 | |
− | + | 在这个例子中,我们充分利用了 Python 生成器来高效处理大型 CSV 文件的组装和传输: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第55行: | 第56行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python">import csv |
from django.http import StreamingHttpResponse | from django.http import StreamingHttpResponse | ||
class Echo: | class Echo: | ||
− | + | """An object that implements just the write method of the file-like | |
interface. | interface. | ||
− | + | """ | |
def write(self, value): | def write(self, value): | ||
− | + | """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): | ||
− | + | """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 = ([ | + | 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= | + | content_type="text/csv") |
− | response['Content-Disposition'] = 'attachment; filename= | + | response['Content-Disposition'] = 'attachment; filename="somefilename.csv"' |
− | return response</ | + | return response</syntaxhighlight> |
</div> | </div> | ||
第91行: | 第92行: | ||
== 使用模板系统 == | == 使用模板系统 == | ||
− | + | 或者,您可以使用 [[../../topics/templates|Django 模板系统]] 生成 CSV。 这比使用方便的 Python <code>csv</code> 模块低级,但为了完整起见,这里提供了解决方案。 | |
− | + | 这里的想法是将项目列表传递给您的模板,并让模板在 [[#id1|:ttag:`for`]] 循环中输出逗号。 | |
− | + | 这是一个示例,它生成与上述相同的 CSV 文件: | |
<div class="highlight-default notranslate"> | <div class="highlight-default notranslate"> | ||
第101行: | 第102行: | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <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= | + | 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', ' | + | ('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</ | + | return response</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | + | 此示例与上一个示例之间的唯一区别在于,此示例使用模板加载而不是 CSV 模块。 其余代码 - 例如 <code>content_type='text/csv'</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"> | ||
− | < | + | <syntaxhighlight lang="html+django">{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}" |
− | {% endfor %}</ | + | {% endfor %}</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | + | 这个模板非常基础。 它只是遍历给定的数据并为每一行显示一行 CSV。 它使用 [[#id3|:tfilter:`addslashes`]] 模板过滤器来确保引号没有任何问题。 | |
第146行: | 第147行: | ||
== 其它文本格式 == | == 其它文本格式 == | ||
− | + | 请注意,这里没有特别针对 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 对象是类文件对象。
下面是一个例子:
代码和注释应该是不言自明的,但是有几件事值得提一下:
- 响应获得一个特殊的 MIME 类型,text/csv。 这告诉浏览器该文档是一个 CSV 文件,而不是一个 HTML 文件。 如果你不这样做,浏览器可能会将输出解释为 HTML,这将导致浏览器窗口中出现丑陋、可怕的 gobbledygook。
- 响应获得一个额外的
Content-Disposition
标头,其中包含 CSV 文件的名称。 这个文件名是任意的; 随心所欲地称呼它。 浏览器将在“另存为...”对话框等中使用它。 - 连接到 CSV 生成 API 很容易:只需将
response
作为第一个参数传递给csv.writer
。csv.writer
函数需要一个类似文件的对象,而 HttpResponse 对象符合要求。 - 对于 CSV 文件中的每一行,调用
writer.writerow
,传递一个 iterable。 - CSV 模块会为您处理引号,因此您不必担心使用引号或逗号对字符串进行转义。 只需传递
writerow()
您的原始字符串,它就会做正确的事情。
输出超大 CSV 文件
在处理生成非常大响应的视图时,您可能需要考虑使用 Django 的 StreamingHttpResponse 代替。 例如,通过流式传输需要很长时间生成的文件,您可以避免负载均衡器丢弃在服务器生成响应时可能会超时的连接。
在这个例子中,我们充分利用了 Python 生成器来高效处理大型 CSV 文件的组装和传输:
使用模板系统
或者,您可以使用 Django 模板系统 生成 CSV。 这比使用方便的 Python csv
模块低级,但为了完整起见,这里提供了解决方案。
这里的想法是将项目列表传递给您的模板,并让模板在 :ttag:`for` 循环中输出逗号。
这是一个示例,它生成与上述相同的 CSV 文件:
此示例与上一个示例之间的唯一区别在于,此示例使用模板加载而不是 CSV 模块。 其余代码 - 例如 content_type='text/csv'
- 是相同的。
然后,使用以下模板代码创建模板 my_template_name.txt
:
这个模板非常基础。 它只是遍历给定的数据并为每一行显示一行 CSV。 它使用 :tfilter:`addslashes` 模板过滤器来确保引号没有任何问题。
其它文本格式
请注意,这里没有特别针对 CSV 的内容——只是特定的输出格式。 您可以使用这些技术中的任何一种来输出您梦寐以求的任何基于文本的格式。 您也可以使用类似的技术来生成任意二进制数据; 有关示例,请参阅 使用 Django 输出 PDF。