JsonResponse и FileResponse Django
Задача следующая: получил список id пользователей через Ajax функцию. На стороне сервера - данные пришли. Ответ вернул в JsonResponse.
Возникла необходимость генерировать шаблон таблицы и вставлять данные пользователей по id. После генерации хочу вызвать FileResponse и скачать в браузере сгенерированный файл.
Но этого у меня не получается. Пытался в теле функции вызвать другую функцию, которая в качестве ответа возвращает FileResponse - не срабатывает, файл не генерится и не скачивается.
Как можно выйти из данной ситуации?
p.s. формировать ссылку на скачаивание - не вариант.
Код:
@csrf_exempt
def multiblank_create(request, slug):
local_storage = request.POST.get('persons')
if local_storage:
temp = json.loads(local_storage)
ids = []
for i in temp:
ids.append(int(i))
print('before')
byte_io = BytesIO()
path_to_blank = os.getcwd() + "\\main\\static\\blanks\\" + slug + "\\"
wb = openpyxl.load_workbook(os.path.join(path_to_blank, 'create.xlsx'))
sheet = wb['Список пользователей']
persons = Person.objects.filter(id__in=ids)
for item in range(1, len(persons)+1):
sheet.insert_rows(3)
for item in range(1, len(persons)+1):
sheet.cell(row=item+1, column=1).value = item+1
wb.save(byte_io)
byte_io.seek(0)
filename = 'Заявка '
msg = 'ok'
return JsonResponse(msg, safe=False)
С исправлениями:
@csrf_exempt
def multiblank_create(request, slug):
local_storage = request.POST.get('persons')
if local_storage:
temp = json.loads(local_storage)
ids = []
for i in temp:
ids.append(int(i))
print('before')
path_to_blank = os.getcwd() + "\\main\\static\\blanks\\" + slug + "\\"
wb = openpyxl.load_workbook(os.path.join(path_to_blank, 'create.xlsx'))
sheet = wb['Список пользователей']
persons = Person.objects.filter(id__in=ids)
for item in range(1, len(persons)+1):
sheet.insert_rows(3)
for item in range(1, len(persons)+1):
sheet.cell(row=item+1, column=1).value = item+1
wb.save('out_test.xlsx')
filename = 'Заявка '
print('near')
response = FileResponse(open('out_test.xlsx', 'rb'))
response['Content-Disposition'] = 'attachment; filename='+filename+ '.xlsx'
response['X-Sendfile'] = filename+ '.xlsx'
return response
Если честно - у меня есть аналогичная функция, только которая генерирует файл Word и скачивается без проблем. Почему здесь такая загвоздка возникает - не могу понять.
Возможен ли вариант, что данный запрос не возможен из-за того, что данные получаю через Ajax - функцию?
Ответы (3 шт):
Попробуйте скачать сгенерированный файл можно таким кодом во view.py:
import os
from django.http import FileResponse
def download_file(request):
dirs = settings.TEMPLATES[0]['DIRS'][0]
filename = 'my_file.xlsx'
response = FileResponse(open(dirs + '/my_file.xlsx', 'rb'))
response['Content-Disposition'] = 'attachment; filename='+filename
response['X-Sendfile'] = filename
return response
Немного поколдовав над кодом, используя подсказки, получилось следующее:
function generateBlank(url) {
if (localStorage['persons'] != "[]" && localStorage['persons'] != undefined) {
$.ajax({
type: "POST",
url: url,
data: {
'persons': localStorage['persons'],
},
success: function (data) {
let a = document.createElement('a');
a.href ="/static/blanks/test/done/" + data.path;
a.download = data.filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
},
error: function (data) {
console.log('Error Server');
},
dataType: "json",
});
};
};
Функция Ajax отправляет данные в функцию Django.
@csrf_exempt
def multiblank_create(request, slug):
local_storage = request.POST.get('persons')
if local_storage:
temp = json.loads(local_storage)
ids = []
for i in temp:
ids.append(int(i))
path_to_blank = os.getcwd() + "\\main\\static\\blanks\\" + slug + "\\"
wb = openpyxl.load_workbook(os.path.join(path_to_blank, 'create.xlsx'))
sheet = wb['Список']
persons = Person.objects.filter(id__in=ids)
...
...
wb.save(os.path.join(path_to_blank+'done\\', 'out_test.xlsx'))
filename = 'Тестовая заявка.xlsx'
data = {
'path': 'out_test.xlsx',
'filename': filename,
}
return JsonResponse(data, safe=False)
На стороне сервера происходит запрос к БД. Заносятся в файл Excel данные. Сохраняются. Далее ответ отправляется в Ajax-seccess и создаеся ссылка на файл. Средсвами JS кликаем по созданной ссылке и инициализируется скачивание файла в браузер. Затем ссылка удаляется.
Код далек от идеала и не претендует на звание лучшего решения на свете, поэтому просьба - если есть что изменить или подкорректировать, то поделитесь своим мнением.
Передача данных из localStorage серверу (или можно получать данные со страницы):
$('#export_goods_excel_file').on('click', function () {
let f_id = localStorage.getItem('f_id');
window.location.href = '/goods/export_goods_excel_file/?f_id=' + f_id;
});
контроллер отвечает за фильтрацию данных, создание xl и отправку пользователю:
def export_goods_excel_file(request):
# получаем данные, которые передали
if request.GET.get('f_id') != '' and request.GET.get('f_id') is not None:
id = request.GET.get('f_id')
# фильтрация
# создал xl файл
workbook = Workbook()
# получил первый лист и присвоил ему название
worksheet = workbook.active
worksheet.title = 'Goods'
# передача данных в xl и т.п. и т.д.
workbook.save(response)
return response
Не лучшее решение, но имеет право на существование.