如何建立 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",
        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 物件符合此要求。

  • 對於 CSV 檔案中的每一列,呼叫 writer.writerow,並傳遞它一個可迭代物件

  • 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)
    return StreamingHttpResponse(
        (writer.writerow(row) for row in rows),
        content_type="text/csv",
        headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
    )

使用樣板系統

或者,您可以使用 Django 樣板系統 來產生 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 檔案

返回頂端