Spec-Zone.ru › Django 2.2

Вывод CSV с Django

В данном документе объясняется, как динамически выводить CSV (Comma Separated Values) с помощью представлений Django. Для этого можно использовать либо библиотеку Python CSV, либо систему шаблонов Django.

Использование библиотеки Python CSV

Python поставляется с библиотекой CSV, csv. Ключевым моментом при её использовании с Django является то, что возможности создания CSV в модуле csv работают с файлоподобными объектами, а объекты HttpResponse Django являются файлоподобными объектами.

Вот пример:

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, что приведёт к некрасивому, пугающему результату в окне браузера.
  • Ответ получает дополнительный Content-Disposition заголовок, который содержит имя файла CSV. Это имя файла произвольное; назовите его как хотите. Оно будет использоваться браузерами в диалоге «Сохранить как…» и т.д.
  • Подключение к API создания CSV простое: просто передайте response в качестве первого аргумента к csv.writer. Функция 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)
    response = StreamingHttpResponse((writer.writerow(row) for row in rows),
                                     content_type="text/csv")
    response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
    return response

Использование системы шаблонов

В качестве альтернативы можно использовать систему шаблонов 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')
    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 = {'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 с помощью Django для примера.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/howto/outputting-csv/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API