---
title: "如何输出 CSV"
version: 4.2
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/4.2/howto/outputting-csv/
canonical: https://djangodocs.dev/zh-hans/4.2/howto/outputting-csv/
---
# 如何输出 CSV

本文介绍如何用 Django 的视图动态输出 CSV (Comma Separated Values)。要达到目的，你可以使用 Python 的 CSV 库或 Django 的模板系统。

## 使用 Python 的 CSV 库

Python 有用一个 CSV 库 [`csv`](https://docs.python.org/3/library/csv.html#module-csv)。它配合 Django 使用的关键是 [`csv`](https://docs.python.org/3/library/csv.html#module-csv) 模块的 CSV 创建行为作用于类文件对象，而 Django 的 [`HttpResponse`](/zh-hans/4.2/ref/request-response/#django.http.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，这会在浏览器窗口展示丑陋的，恐怖的官样文章。
- 相应还包括一个额外的 `Content-Disposition` 头，其中包含了 CSV 文件的名称。文件名是任意的；随便你怎么叫。它会被浏览器在 "保存为……" 对话框中用到。
- 你需将 `response` 作为第一个参数传给 `csv.writer` 来接入生成 CSV API 。 `csv.writer` 函数期望一个类文件对象，而 [`HttpResponse`](/zh-hans/4.2/ref/request-response/#django.http.HttpResponse) 对象满足该要求。
- 要按行输出 CSV 文件，调用 `writer.writerrow`，传入一个 [iterable](https://docs.python.org/3/glossary.html#term-iterable) 参数。
- CSV 模块为你处理了引号，所以你无需担心包含引号或逗号的字符串的转义问题。你需要为 `writerow()` 传入原始字符串，它为你处理好一切。

### 输出超大 CSV 文件

当处理生成很多回复的视图时，你可能要考虑使用 Django 的 [`StreamingHttpResponse`](/zh-hans/4.2/ref/request-response/#django.http.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"'},
    )
```

## 使用模板系统

或者，你也能用 [Djano 模板系统](/zh-hans/4.2/topics/templates/) 生成 CSV。这比使用方便的 [`csv`](https://docs.python.org/3/library/csv.html#module-csv) 模块级别低点，但是，解决方案就在这，你可以选。

办法就是将项目列表传给模板，让模板在 [`for`](/zh-hans/4.2/ref/templates/builtins/#std-templatetag-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`。

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

这个简短的模板遍历所给的数据，并为每行生成一个 CSV 行。它利用 [`addslashes`](/zh-hans/4.2/ref/templates/builtins/#std-templatefilter-addslashes) 模板过滤器确保引号不会引发任何问题。

## 其它文本格式

注意，这里并没有太多特定于 CSV 的内容——仅是特定的输出格式。你可以使用其中任意一种输出你能想到文本内容。你也能用类似的技术生成任意二进制数据；参考 [如何创建 PDF 文件](/zh-hans/4.2/howto/outputting-pdf/) 的例子。
