下载按钮重定向到错误页面
Download Button Redirecting to Wrong Page
在我的 Django 项目中,用户将一个 Elasticsearch 查询提交到一个表单中,它 returns 从该查询生成一个可下载的报告。我们进行了一些更改,现在我正在尝试让 returns 报告的部分再次发挥作用。但是,我 运行 遇到了我的 url 模式的问题,它应该调用视图函数来下载报告。
我有一个 Download Report
按钮,该按钮会在报告生成完成后出现(由 Ajax 请求检查)。这个想法是用户单击按钮,报告将出现在他们的下载文件夹中。但是,当我单击按钮时,它会将我发送到 /report/return_doc/
而不是 /return_doc/
。
将用户发送到/return_doc/
的逻辑是它与我视图中的return_doc功能相关联,但是我可以触发此功能并在不刷新[的情况下将报告下载给用户吗? =45=] 他们要新的 url?还是我需要做一些完全不同的事情才能让这个按钮起作用?
错误信息
Page not found (404)
Request Method: GET
Request URL: http://0.0.0.0:0001/report/return_doc/
Using the URLconf defined in audit_tool_app.urls, Django tried these URL patterns, in this order:
admin/
accounts/
form/
report/ [name='form']
report/ ^static/(?P<path>.*)$
check_progress/ [name='check_progress']
return_doc/ [name='return_doc']
[name='home']
^static/(?P<path>.*)$
The current path, report/return_doc/, didn't match any of these.
audit_tool/urls.py
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', views.get_query, name='form'),
] + static(settings.STATIC_URL, document_root=settings.STAT)
audit_tool_app/urls.py
"""audit_tool_app URL Configuration"""
from django.contrib import admin
from django.urls import include, path
from django.views.generic.base import TemplateView
from django.conf import settings
from django.conf.urls.static import static
from audit_tool import views
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('form/', include('audit_tool.urls')),
path('report/', include('audit_tool.urls')),
path('check_progress/', views.check_progress, name='check_progress'),
path('report/return_doc/', views.return_doc, name='return_doc'),
path('', TemplateView.as_view(template_name='home.html'), name='home'),
] + static(settings.STATIC_URL, document_root=settings.STAT)
views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from docx import Document
import os
import threading
from .forms import QueryForm
from .models import *
import time
@login_required
def get_query(request):
if request.method == 'POST':
form = QueryForm(request.POST)
if form.is_valid():
query = form.cleaned_data["query"]
fn = "report_" + str(time.time()).replace(".", "_") + ".docx"
t = threading.Thread(target=generate_doc, args=(query, fn))
t.start()
return render(request, "audit_tool/check.html", {"fn": fn})
else:
return HttpResponse("Your query does not appear to be valid. Please enter a valid query and try again.")
else:
form = QueryForm()
return render(request, 'audit_tool/form_template.html', {'form': form})
@login_required
def check_progress(request):
"""
Returns status of document generation
"""
fn = request.POST["filename"]
file = "/app/created_files/" + fn
if not os.path.exists(file):
return JsonResponse({"report_in_progress": 1})
else:
return JsonResponse({"report_in_progress": 0})
@login_required
def return_doc(request):
"""
Returns report to user
"""
fn = request.POST["filename"]
file = "/app/created_files/" + fn
doc = Document(file)
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename={}'.format(fn)
doc.save(response)
return response
check.html
<!-- templates/django_audit/check.html -->
{% extends 'base_login.html' %}
{% block title %}Please wait{% endblock %}
{% load static %}
{% block content %}
<script type='text/javascript' src="{% static "bootstrap/js/jquery/1.7.1/jquery.min.js" %}"></script>
<script type="text/javascript">
$(document).ready( function() {
var fn = $('#fn').val()
var checkInterval = setInterval(isFileComplete, 3000); //3000 is 3 seconds
function isFileComplete() {
$.ajax({
url: '/check_progress/',
type: 'POST',
data: {
'filename': fn,
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
dataType: 'json',
success: function (data) {
if (data.report_in_progress == 1) {
$("#download-button").hide();
} else {
$("#download-button").show();
clearInterval(checkInterval);
}
}
});
}
});
</script>
<p><br></p>
<p><br></p>
<div class="alert alert-primary" role="alert">
<p>Generating {{fn}}...please wait until the Download Report button appears.</p>
<button type="button" id="download-button" value="Download" onclick="window.open('return_doc')">Download Report</button>
</div>
<input id="fn" type=hidden value="{{fn}}">
{% endblock %}
你让这件事变得比它需要的要难得多。
A POST 用于当您想要 发送 数据到后端时,通常是为了更新数据库中的某些内容,或者对于您的 get_query 查看创建一个文件。但是,在 return_doc 的情况下,您没有这样做;您正在检索 已经创建的东西,即文件。所以你应该继续照原样发送GET请求。
不过,您没有做的事情是发送您要检索的文件的名称。在 GET 请求中,它位于查询参数中 URL 的末尾 - 例如 /mypath/?filename=myfilename
。所以只需在您的路径中使用它:
onclick="window.open('/return_doc/?filename={{fn}}')"
并且在视图中:
fn = request.GET["filename"]
(但请注意,更好的解决方案是在媒体目录中创建您的文件,然后服务器可以直接访问和提供该文件,而无需 return_doc URL 或查看。)
在我的 Django 项目中,用户将一个 Elasticsearch 查询提交到一个表单中,它 returns 从该查询生成一个可下载的报告。我们进行了一些更改,现在我正在尝试让 returns 报告的部分再次发挥作用。但是,我 运行 遇到了我的 url 模式的问题,它应该调用视图函数来下载报告。
我有一个 Download Report
按钮,该按钮会在报告生成完成后出现(由 Ajax 请求检查)。这个想法是用户单击按钮,报告将出现在他们的下载文件夹中。但是,当我单击按钮时,它会将我发送到 /report/return_doc/
而不是 /return_doc/
。
将用户发送到/return_doc/
的逻辑是它与我视图中的return_doc功能相关联,但是我可以触发此功能并在不刷新[的情况下将报告下载给用户吗? =45=] 他们要新的 url?还是我需要做一些完全不同的事情才能让这个按钮起作用?
错误信息
Page not found (404)
Request Method: GET
Request URL: http://0.0.0.0:0001/report/return_doc/
Using the URLconf defined in audit_tool_app.urls, Django tried these URL patterns, in this order:
admin/
accounts/
form/
report/ [name='form']
report/ ^static/(?P<path>.*)$
check_progress/ [name='check_progress']
return_doc/ [name='return_doc']
[name='home']
^static/(?P<path>.*)$
The current path, report/return_doc/, didn't match any of these.
audit_tool/urls.py
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', views.get_query, name='form'),
] + static(settings.STATIC_URL, document_root=settings.STAT)
audit_tool_app/urls.py
"""audit_tool_app URL Configuration"""
from django.contrib import admin
from django.urls import include, path
from django.views.generic.base import TemplateView
from django.conf import settings
from django.conf.urls.static import static
from audit_tool import views
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('form/', include('audit_tool.urls')),
path('report/', include('audit_tool.urls')),
path('check_progress/', views.check_progress, name='check_progress'),
path('report/return_doc/', views.return_doc, name='return_doc'),
path('', TemplateView.as_view(template_name='home.html'), name='home'),
] + static(settings.STATIC_URL, document_root=settings.STAT)
views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from docx import Document
import os
import threading
from .forms import QueryForm
from .models import *
import time
@login_required
def get_query(request):
if request.method == 'POST':
form = QueryForm(request.POST)
if form.is_valid():
query = form.cleaned_data["query"]
fn = "report_" + str(time.time()).replace(".", "_") + ".docx"
t = threading.Thread(target=generate_doc, args=(query, fn))
t.start()
return render(request, "audit_tool/check.html", {"fn": fn})
else:
return HttpResponse("Your query does not appear to be valid. Please enter a valid query and try again.")
else:
form = QueryForm()
return render(request, 'audit_tool/form_template.html', {'form': form})
@login_required
def check_progress(request):
"""
Returns status of document generation
"""
fn = request.POST["filename"]
file = "/app/created_files/" + fn
if not os.path.exists(file):
return JsonResponse({"report_in_progress": 1})
else:
return JsonResponse({"report_in_progress": 0})
@login_required
def return_doc(request):
"""
Returns report to user
"""
fn = request.POST["filename"]
file = "/app/created_files/" + fn
doc = Document(file)
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
response['Content-Disposition'] = 'attachment; filename={}'.format(fn)
doc.save(response)
return response
check.html
<!-- templates/django_audit/check.html -->
{% extends 'base_login.html' %}
{% block title %}Please wait{% endblock %}
{% load static %}
{% block content %}
<script type='text/javascript' src="{% static "bootstrap/js/jquery/1.7.1/jquery.min.js" %}"></script>
<script type="text/javascript">
$(document).ready( function() {
var fn = $('#fn').val()
var checkInterval = setInterval(isFileComplete, 3000); //3000 is 3 seconds
function isFileComplete() {
$.ajax({
url: '/check_progress/',
type: 'POST',
data: {
'filename': fn,
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
dataType: 'json',
success: function (data) {
if (data.report_in_progress == 1) {
$("#download-button").hide();
} else {
$("#download-button").show();
clearInterval(checkInterval);
}
}
});
}
});
</script>
<p><br></p>
<p><br></p>
<div class="alert alert-primary" role="alert">
<p>Generating {{fn}}...please wait until the Download Report button appears.</p>
<button type="button" id="download-button" value="Download" onclick="window.open('return_doc')">Download Report</button>
</div>
<input id="fn" type=hidden value="{{fn}}">
{% endblock %}
你让这件事变得比它需要的要难得多。
A POST 用于当您想要 发送 数据到后端时,通常是为了更新数据库中的某些内容,或者对于您的 get_query 查看创建一个文件。但是,在 return_doc 的情况下,您没有这样做;您正在检索 已经创建的东西,即文件。所以你应该继续照原样发送GET请求。
不过,您没有做的事情是发送您要检索的文件的名称。在 GET 请求中,它位于查询参数中 URL 的末尾 - 例如 /mypath/?filename=myfilename
。所以只需在您的路径中使用它:
onclick="window.open('/return_doc/?filename={{fn}}')"
并且在视图中:
fn = request.GET["filename"]
(但请注意,更好的解决方案是在媒体目录中创建您的文件,然后服务器可以直接访问和提供该文件,而无需 return_doc URL 或查看。)