Вывод 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/