用Django输出CSV

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

使用Python CSV库

Python comes with a CSV library, 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.writer的第一个参数即可。 csv.writer函数需要一个类似文件的对象,而HttpResponse对象适合账单。
  • 对于CSV文件中的每一行,调用writer.writerow,传递一个可迭代对象,如列表或元组。
  • CSV模块负责为您引用,所以您不必担心使用引号或逗号来转义字符串。 Just pass writerow() your raw strings, and it’ll do the right thing.

流大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 template system生成CSV。 这比使用方便的Python csv模块要低,但是为了完整性,这里给出了解决方案。

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

下面是一个例子,它生成与上面相同的CSV文件:

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

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 = Context({
        '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,只是具体的输出格式。 您可以使用这些技术中的任何一种来输出您可以梦想的任何基于文本的格式。 您也可以使用类似的技术来生成任意的二进制数据;例如,请参阅Outputting PDFs with Django