Мне нужно, чтобы Django автоматически загружал сгенерированный файл.
Пробовал разные решения в интернете, ни одно не работает.
Views.py
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
response = FileResponse(open(zip_filepath, 'rb'), as_attachment=True)
return response
raise Http404
Шаблон: код формы POST.
$(document).on('submit', '#productForm', function(e){
e.preventDefault();
var inputFilePath = document.getElementById('sourceFileInput').files.item(0).name;
$.ajax({
method: 'POST',
url: 'validate/',
data: {
source_file: inputFilePath,
region: $("#Region-choice").val(),
product_type: $("#Product-type").val()}
})
.done(function(){
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
document.getElementById('lblStatusContent').innerHTML = "Success!"
})
.fail(function(req, textStatus, errorThrown) {
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
alert("Something went wrong!:" + textStatus + ' ' + errorThrown )
});
});
});
@dirkgroten хорошо, ничего не происходит, когда возвращается ответ. Я ожидаю, что файл будет автоматически загружен, когда вернется FileResponse.
но если FileResponse
возвращается, вы либо увидите файл в своем браузере, либо он будет загружен. Что вы видите на вкладке «Сеть» вашего браузера? какие заголовки ответа? Вы видите, что файл возвращается туда? И установлен ли заголовок Content-Disposition для ответа?
Не могли бы вы сделать запрос GET? Он возвращает 404, потому что файл не существует? Вы пытались сделать простое представление, которое возвращает FileResponse, а затем работать в обратном направлении, добавляя больше своей логики?
@dirkgroten да, я вижу файл в заголовках ответов. А для Content-Dispositioin
, согласно официальной документации, Если as_attachment=True, устанавливается заголовок Content-Disposition, который просит браузер предложить файл пользователю для загрузки., кажется, мне больше не нужно устанавливать его вручную. И в ответе написано Content-Disposition: вложение; имя_файла="Final.zip", выглядит правильно.
что делает запрос POST? Если это обычная отправка формы html или это xhr?
@dirkgroten да, из обычной HTML-формы.
@shillingt Файл существует, и он также находится в заголовках ответов.
вы пробовали разные браузеры? Мне интересно, всегда ли ответ на POST с файлом для загрузки обрабатывается одинаково. Обратите внимание, что, как правило, вы должны перенаправлять всегда на POST, чтобы у вас был GET для получения страницы успеха. Это потому, что в противном случае вы «сломаете» кнопку «Назад».
а вы пробовали что-то еще, кроме zip-файла? Я думаю, что браузер может быть причиной здесь.
@dirkgroten Да, тоже пробовал в FF, все то же самое. Для перенаправления я сомневаюсь, что мне следует это использовать, потому что я хочу оставаться на той же странице и не обновлять страницу.
@dirkgroten Пробовал с простым и небольшим файлом .txt, волшебства не произошло...
Также может быть лучше разместить код шаблона здесь...
вы сказали, что это обычная запись в формате html, но, видимо, это не так: вы делаете запрос XHR!
@dirkgroten хорошо, тогда я их перепутал ... Может ли быть проблема в этом?
да, конечно, вы ничего не делаете с файлом, который возвращается вашим обработчиком done
.
Возможный дубликат Скачать файл с помощью jQuery.Ajax
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
with open(zip_filepath, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(zip_filepath)
return response
raise Http404
Попробуйте встроенный вместо вложения
В сети ответ уже показывает Content-Disposition: inline;
Это может сломаться, если путь к файлу содержит точку с запятой.
Невозможно загрузить файлы на ваш компьютер с помощью запроса ajax (XHR). Таким образом, вам нужно фактически перенаправить пользователя (настройка window.location
) в представление, которое загружает файл. Или вы можете добавить в результате успешного POST кнопку текущую страницу, чтобы пользователь мог загрузить файл. В любом случае вам нужно переместить загрузку файла в другое представление, чтобы его можно было получить с помощью стандартного запроса GET.
Но ваш код для возврата файла в Django (с использованием FileResponse
) правильный.
Также есть объяснение с альтернативным способом сделать это здесь
Хорошо, допустим, кнопка загрузки появляется после успешного POST, как можно отправить возвращенный FileResponse
функции нажатия кнопки? Возможно глупый вопрос, но я новичок в JS...
Кнопка — это просто ссылка <a href="> на другое представление Django (GET), где вы возвращаете FileResponse. Поэтому вам нужно написать другое представление, которое возвращает файл. Это означает, что ваше представление POST должно возвращать какой-то идентификатор файла, который затем можно использовать в GET.
Итак, вот так: 1. Первая функция View принимает запрос POST для создания файла, который будет загружен; 2. Напишите вторую функцию в представлении, чтобы вернуть FileResponse 3. Используйте window.location
в успешном POST, чтобы перенаправить на URL-адрес функции представления, созданной на предыдущем шаге, чтобы ПОЛУЧИТЬ файл (не знаю, как, проверим.)
Да, это одно из возможных решений. Ваш 1-й просмотр должен вернуться. jsonResponse с URL-адресом файла (чтобы ваше второе представление «знало», какой файл отправить обратно). Если вы используете window.location, пользователь увидит обновление страницы (на пустую страницу) перед началом загрузки. Вот почему я подумал, что кнопка будет работать лучше, поскольку пользователь просто останется на текущей странице. Но легко попробовать оба, чтобы решить, что лучше для пользователя.
"не работает" не очень описательно. Что просходит?