У меня есть задача сельдерея, которая создает PDF-файлы одним нажатием кнопки.
Когда кнопка нажата, сторона javascript будет продолжать проверять, пока задача не будет выполнена, и когда она будет выполнена, она будетскачать файл.Я подумал, что рекурсивный подход подойдет:
$(".getPdf").on('click', function(event) {
// Grab the clicked object ID and the filename stored on the data attributes
var thisId = $(this).data('runid');
var filename = $(this).data('filename');
var taskID = "None";
var pdfStatus = "None";
// Run download function
downloadPdf(filename, taskID, pdfStatus);
function downloadPdf(filename, taskID, pdfStatus) {
// Send a POST request to Django's RunsView with the Run ID, pdf filename, task ID and pdfStatus (if any)
$.post({
url: "{% url 'runs' %}",
data: {
csrfmiddlewaretoken: "{{ csrf_token }}",
id: thisId,
filename: filename,
task_id: taskID,
},
success: function(data) {
// Split the returned string to separate the task ID [0] from the status [1]
var taskID = data.split(";")[0];
var pdfStatus = data.split(";")[1];
// Convert the pdfStatus Python bools into JavaScript bools
if (pdfStatus == "False") {
pdfStatus = false;
} else if (pdfStatus == "True") {
pdfStatus = true;
};
if (!pdfStatus) {
console.log("Repeat function.");
downloadPdf(filename, taskID, pdfStatus);
} else {
console.log("Download PDF");
window.open("data:application/pdf;base64," + data);
};
},
traditional: true
}).done();
};
});
Фактическая сторона JavaScript загрузки PDF достаточно проста.Я отправляю идентификатор объекта, который я хочу сгенерировать в формате PDF (« Run »), вместе с именем файла, которое должно иметь (это создается на части get вид Django на той же странице) и пустой идентификатор задачи сельдерея (задача, конечно, еще не была создана).Ответ, который я получаю, представляет собой строку из «идентификатора задачи сельдерея»;с False, если задача еще не выполнена, поэтому я повторяю запрос POST.
С серверной стороны я обрабатываю запрос POST в зависимости от того, присутствует ли идентификатор задачи:
def post(self, request):
# Get the args from the incoming request
run_id = request.POST.get('id')
filename = request.POST.get('filename')
task_id = request.POST.get('task_id')
if run_id and task_id == "None":
# Database and Django stuff happens here for a few lines...
# Fire off a Celery task to generate the PDF file asynchronously
pdf_task = create_pdf.delay(sensor, range_period)
response_string = str(pdf_task.task_id) + ";" + str(AsyncResult(pdf_task.task_id).ready())
return HttpResponse(response_string)
elif task_id != "None":
pdf_done = AsyncResult(task_id).ready() # If this is false, send the task ID back with a False
if not pdf_done:
response_string = str(task_id) + ";" + str(pdf_done)
return HttpResponse(response_string)
# Otherwise send the PDF back
else:
pdf_task = AsyncResult(task_id)
pdf_file = pdf_task.result
pdf_file_location = settings.MEDIA_ROOT + '/reports/' + pdf_file
# response = HttpResponse(content_type='application/pdf')
# response['Content-Disposition'] = 'attachment; filename={}'.format(pdf_task.result)
# # return response
try:
# with open(pdf_file_location, 'r') as pdf:
# response = HttpResponse(pdf.read(), content_type='application/pdf')
# response['Content-Disposition'] = 'attachment; filename="' + pdf_task.result + '"'
# pdf.close()
return FileResponse(open(pdf_file_location, 'rb'), content_type='application/pdf')
except IOError:
print("File does not exist, check above.")
return response
Я пошел дальше и ушел в попытках заставить загрузку файлов работать с запросом AJAX.Пока что тот, который не закомментирован, на самом деле возвратил строку кодированного текста во внешний интерфейс, но я не уверен, как его декодировать, в итоге я получаю вкладку, которая выглядит следующим образом:
Итак, закодированный PDF-файл достигает внешнего интерфейса после обработки файла (эта часть в порядке), но я недостаточно хорош в JavaScript, чтобы понять, какпревратить закодированную строку в файл PDF.