本文档介绍如何使用django视图动态输出csv(逗号分隔值)。为此,您可以使用python csv库或django模板系统。
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",
headers={"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文件的名称。这个文件名是任意的;您可以随意调用它。浏览器将在“另存为…”对话框等中使用它。
您可以通过 response
作为第一个论点 csv.writer
. 这个 csv.writer
函数需要一个类似文件的对象,并且 HttpResponse
对象适合帐单。
对于csv文件中的每一行,请调用 writer.writerow
通过一个 iterable .
CSV模块负责为您引用,因此您不必担心对带有引号或逗号的字符串进行转义。通过 writerow()
你的原始弦,它会做正确的事。
当处理产生非常大响应的视图时,您可能需要考虑使用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)
return StreamingHttpResponse(
(writer.writerow(row) for row in rows),
content_type="text/csv",
headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
)
或者,您可以使用 Django template system 生成csv。这比使用方便的python要低 csv
模块,但为了完整性,这里给出了解决方案。
这里的想法是将项目列表传递给模板,并让模板在 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",
headers={"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。它使用 addslashes
模板过滤器,以确保报价没有任何问题。
注意,这里并没有非常具体的csv——只是具体的输出格式。您可以使用这些技术中的任何一种来输出任何您梦寐以求的基于文本的格式。您还可以使用类似的技术生成任意二进制数据;请参见 如何创建PDF文件 举个例子。
12月 18, 2023