Здесь описывается как генерировать CSV (Comma Separated Values) с помощью представлений Django. Для этого нам понадобится библиотека для работы с CSV или шаблоны Django.
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')
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
Код и комментарии должны быть понятны, но на некоторые вещи стоит обратить внимание:
Ответу устанавливается определённый тип text/csv, этим мы говорим браузеру, что передаём файл в формате CSV, а не HTML. Если этого не сделать, то браузер будет пытаться отобразить документ как HTML, что может испугать пользователя.
Ответ также имеет дополнительный заголовок Content-Disposition, в котором содержится имя файла. Оно будет подставлено в окне сохранения файла и других случаях.
Для генерации CSV просто передайте response первым аргументом в csv.writer. Вообще, в csv.writer можно передавать любой файловый объект.
Для каждой строки в CSV файле вызовите writer.writerow, передав итерируемый объект (список или кортеж).
Модуль для работы с CSV сам умеет экранировать спецсимволы, так что просто передавайте в writerow() свои данные.
Поддержка Unicode в Python 2
В Django работа ведётся со строками формата Unicode, однако csv из Python 2 их не поддерживает. Вот несколько вариантов решения проблемы:
Ручная перекодировка всех Unicode объектов.
Использование UnicodeWriter, который описан в csv module’s examples section.
Использование python-unicodecsv module, который приходит на замену csv. Там с Unicode всё отлично.
За подробной информацией можно обратиться к документации по модулю csv.
При работе с представлениями, которые генерируют ответ с большим количеством данных, вам следует использовать StreamingHttpResponse. Стримя большой файл, можно избежать обрыва подключения по таймауту при использовании балансировщика нагрузки.
В этом примере мы используем генераторы 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 template system для генерации CSV. Это низкоуровневое решение представлено здесь для полноты картины.
Суть в том, чтобы обработать список элементов вашим шаблоном и вывести в цикле с помощью, например, for.
Ниже пример реализации:
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
Единственное отличие между этим примером и предыдущим состоит в том, что используется шаблон 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 на Django).
Mar 31, 2016