Вывод 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()ваши исходные строки, и он сделает правильное дело.
Обработка Unicode в Python 2
Модуль csv Python 2 не поддерживает Unicode-ввод. Поскольку Django использует Unicode внутри, это означает, что строки, считанные из источников, таких как HttpRequest, потенциально могут вызвать проблемы. Есть несколько вариантов обработки этого:
- Вручную кодировать все Unicode-объекты в совместимую кодировку.
- Использовать класс
UnicodeWriter, предоставленный в разделе примеров модуля csv. - Использовать модуль python-unicodecsv, который призван быть прямой заменой для
csvи корректно обрабатывать Unicode.
Дополнительную информацию см. в документации Python по модулю csv.
Потоковая передача больших файлов CSV
При работе с представлениями, генерирующими очень большие ответы, можно рассмотреть использование StreamingHttpResponse Django. Например, передача файла, который занимает много времени для генерации, позволяет избежать отключения соединения балансировщиком нагрузки, что могло бы произойти, если бы сервер генерировал ответ в течение длительного времени.
В этом примере мы в полной мере используем генераторы Python для эффективной сборки и передачи большого файла CSV:
import csv
from django.utils.six.moves import range
from django.http import StreamingHttpResponse
class Echo(object):
"""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, Context
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 = Context({
'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/1.11/howto/outputting-csv/