Как позволить пользователю скачать файл после завершения процесса в Django?
Я начинающий в Django. Я пытаюсь позволить пользователю скачать файл после завершения определенного процесса.
Здесь view.py
. После завершения процесса отображается кнопка загрузки. Пользователи могут загрузить файл с именем WS_имя_файла+'.xlsx', нажав на кнопку загрузки.
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
if request.method == 'POST':
student = StudentForm(request.POST, request.FILES)
if student.is_valid():
handle_uploaded_file(request.FILES['file'])
firstname= student.cleaned_data.get("firstname")
lastname= student.cleaned_data.get("lastname")
### Processing ###
WS_file_name = lastname + firstname + newfile
Toollist_Raw = pd.read_excel(Toollist_path+Toollist_file_name)
WS_file = xlsxwriter.Workbook(WS_file_name+'.xlsx')
WS_file.close()
file_source = WS_Path + WS_file_name+'.xlsx'
Toollist_Raw.to_excel(file_source, sheet_name='CALM_Toollist',index=False)
### Process had completed, users can click download button to download the file ###
context= {'username': firstname, 'version':lastname,}
return render(request, 'template_Download.html', context)
else:
student = StudentForm()
return render(request,"template_Form.html",{'form':student})
##### Download Functions #####
import os
from django.http import FileResponse
def download_file(request):
# Define Django project base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Define file name
filename = WS_file_name+'.xlsx'
# Define the full file path
filepath = BASE_DIR + '/Capital_Report_Website/Download_Files/Baseline_Cleanup_Toollist_vs_CALM_Download/' + filename +'.xlsx'
return FileResponse(open(filepath, 'rb'), as_attachment=True)
Ниже приведен код template_Form.html
. Эта страница позволяет пользователю заполнить информацию, которая используется для обработки файла.
<form method="POST" class="post-form" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Generate Report</button>
</form>
Ниже приведен код template_Download.html
. Эта страница отображается после завершения процесса. Кнопка загрузки находится прямо на этой странице.
<h3>Hi, {{username}} your toollist {{version}} vs CALM report is completed.</h3>
<a href="http://localhost/toollistvscalm/download/">Download</a>
Ниже приведен код urls.py
, который используется для вызова функций в views.py
.
urlpatterns = [
path('admin/', admin.site.urls),
path('toollistvscalm/', views.index),
path('toollistvscalm/download/', views.download_file),
]
После нажатия на кнопку загрузки появляется следующая ошибка.
name 'WS_file_name' is not defined
Я перепробовал все, чтобы исправить это, но тщетно. Пожалуйста, помогите мне.
Ок, проблема в том, что в вашей функции download_file
переменная WS_file_name
не определена.
Поскольку функция download_file
не может взаимодействовать с функцией index
(по крайней мере, так, как вы ее настроили), вам нужно заполнить переменную WS_file_name
точно таким же именем файла, которое вы дали ей, когда сохраняли файл в функции index
.
Тогда все будет хорошо!
Приведу пример с жестко заданными именами файлов, которые должны работать:
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
if request.method == 'POST':
student = StudentForm(request.POST, request.FILES)
if student.is_valid():
handle_uploaded_file(request.FILES['file'])
firstname= student.cleaned_data.get("firstname")
lastname= student.cleaned_data.get("lastname")
### Processing ###
WS_file_name = "hardcoded_filename" # HERE FILENAME
Toollist_Raw = pd.read_excel(Toollist_path+Toollist_file_name)
WS_file = xlsxwriter.Workbook(WS_file_name+'.xlsx')
WS_file.close()
file_source = WS_Path + WS_file_name+'.xlsx'
Toollist_Raw.to_excel(file_source, sheet_name='CALM_Toollist',index=False)
### Process had completed, users can click download button to download the file ###
context= {'username': firstname, 'version':lastname,}
return render(request, 'template_Download.html', context)
else:
student = StudentForm()
return render(request,"template_Form.html",{'form':student})
##### Download Functions #####
import os
from django.http import FileResponse
def download_file(request):
# Define Django project base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Define file name
filename = "hardcoded_filename" +'.xlsx' # HERE SAME FILENAME
# Define the full file path
filepath = BASE_DIR + '/Capital_Report_Website/Download_Files/Baseline_Cleanup_Toollist_vs_CALM_Download/' + filename +'.xlsx'
return FileResponse(open(filepath, 'rb'), as_attachment=True)
Но учтите следующее:
Это требует, чтобы вы хранили все эти файлы на вашей хост-машине. Мне кажется, что вам следует перенести раздел ### Processing ###
в функцию download_file
. Таким образом, вам не нужно будет хранить файл на вашей машине, и вы сможете представить его пользователю "на лету".
Редактирование:
Поскольку ОП хочет динамические имена файлов - вот вам...
models.py
class Student(models.Model):
firstname = models.CharField(max_lenght=30)
lastname = models.CharField(max_lenght=30)
path_to_xlsx = models.FilePathField(null=True, blank=True) # don't know if this works, or just put a default in.
views.py
def index(request):
[...]
if student.is_valid():
the_student = Student.objects.get(pk=<your-student>) # somehow grab your student here
[... file processing ...]
the_student.path_to_xlsx = os.path.join(path_to_your_file)
the_student.save()
the_student = student.save()
def download_file(request):
[...]
the_student = Student.objects.get(pk=<your-student>) # somehow grab your student here
return FileResponse(open(the_student.path_to_xlsx, 'rb'), as_attachment=True)
Но все же я не считаю это хорошим вариантом, так как файлы excel будут загрязнять файловую систему и хранилище вашей хост-машины