• 3.1
  • 3.2
  • 5.0
  • Версия документации: 6.1

Генерация CSV на Django

Здесь описывается как генерировать CSV (Comma Separated Values) с помощью представлений Django. Для этого нам понадобится библиотека для работы с CSV.

Использование библиотеки для работы с CSV

Python поставляется с библиотекой csv. Фишка в том, что этот модуль работает с файловыми объектами, которым как раз и является 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

Код и комментарии должны быть понятны, но на некоторые вещи стоит обратить внимание:

  • Ответу устанавливается определённый тип text/csv, этим мы говорим браузеру, что передаём файл в формате CSV, а не HTML. Если этого не сделать, то браузер будет пытаться отобразить документ как HTML, что может испугать пользователя.

  • Ответ также имеет дополнительный заголовок Content-Disposition, в котором содержится имя файла. Оно будет подставлено в окне сохранения файла и других случаях.

  • Вы можете подключиться в API генерации CSV, передав response первым аргументом в csv.writer. Функция csv.writer ожидает файловый объект и объект HttpResponse как раз подойдет в качестве аргумента.

  • Для каждой строки в CSV файле вызывайте writer.writerow, передавая итерируемый объект (список или кортеж).

  • Модуль для работы с CSV сам умеет экранировать спецсимволы, не стоит волноваться об экранировании кавычек и запятых. Передавайте в writerow() свои данные и всё будет сделано правильно.

Стриминг больших CSV файлов

При работе с представлениями, которые генерируют ответ с большим количеством данных, вам следует использовать 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. Это низкоуровневое решение представлено здесь для полноты картины.

Суть в том, чтобы обработать список элементов вашим шаблоном и вывести в цикле с помощью, например, for.

Ниже представлен пример реализации:

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 hardcoded 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

Единственное отличие между этим примером и предыдущим состоит в том, что используется шаблон Django, а не модуль 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 файлы).

Back to Top