Как создать вывод CSV
В данном документе объясняется, как динамически выводить CSV (Comma Separated Values) с помощью представлений Django. Для этого можно использовать либо библиотеку 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. Это имя файла произвольное; используйте любое, что вам нравится. Оно будет использоваться браузерами в диалоговом окне «Сохранить как» и т. д. - Можно подключиться к API создания CSV, передав
responseв качестве первого аргумента функцииcsv.writer. Функцияcsv.writerожидает объект, подобный файлу, а объектыHttpResponseподходят для этого. - Для каждой строки в вашем файле CSV вызывайте функцию
writer.writerow, передавая ей итерируемый объект. - Модуль CSV сам позаботится о кавычках, поэтому вам не нужно беспокоиться об экранировании строк с кавычками или запятыми в них. Передавайте
writerow()ваши исходные строки, и он сделает все правильно.
Потоковая передача больших файлов CSV
При работе с представлениями, генерирующими очень большие ответы, можно рассмотреть использование Django's 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 для примера.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.0/howto/outputting-csv/