下载按钮重定向到错误页面

Posted

技术标签:

【中文标题】下载按钮重定向到错误页面【英文标题】:Download Button Redirecting to Wrong Page 【发布时间】:2019-11-16 05:34:48 【问题描述】:

在我的 Django 项目中,用户将 Elasticsearch 查询提交到表单中,它会返回从该查询生成的可下载报告。我们进行了一些更改,现在我正试图让返回报告的部分再次工作。但是,我的 url 模式遇到了一个问题,应该调用 view 函数来下载报告。

我有一个Download Report 按钮,一旦生成报告(由 Ajax 请求检查),就会出现该按钮。这个想法是用户将单击该按钮,并且报告将出现在他们的下载文件夹中。但是,当我单击按钮时,它会将我发送到 /report/return_doc/ 而不是 /return_doc/

将用户发送到/return_doc/ 的逻辑是它与我的视图中的return_doc 函数相关联,但是我可以触发该函数并将报告下载给用户而不刷新页面/将它们发送到新的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 %

【问题讨论】:

使用anchor tag 作为按钮怎么样?你试过吗? @Paolo 我试过&lt;a href="/return_doc/"&gt;Download Report&lt;/a&gt; 它给了我MultiValueDictKeyError at /report/return_doc/ \\ 'filename' \\ /app/icm_audit_tool/views.py in return_doc \\ 47. fn = request.POST["filename"] \\ /usr/local/lib/python3.7/site-packages/django/utils/datastructures.py in __getitem__ \\ 79. raise MultiValueDictKeyError(key) 初始错误通过添加一个前导斜杠可以轻松修复:onclick="window.open('/return_doc/')"&gt;Download - 但这只会导致与上述相同的错误,因为您实际上并没有发布文件名。 改用request.POST.get('filename', None)。无论如何,按钮是否会在点击时发送任何数据? 您似乎没有任何帖子数据filename 正在发送到您的视图。 @carousallie 【参考方案1】:

你做的比它需要的要困难得多。

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 或视图。)

【讨论】:

我有一种可怕的感觉,我让它变得比需要的更困难。感谢您的详尽解释和解决方案!

以上是关于下载按钮重定向到错误页面的主要内容,如果未能解决你的问题,请参考以下文章

Sentry 捕获错误时重定向到新页面

如果发生数据库错误,如何将页面重定向到其他页面

为啥我的 mvc 项目重定向到默认的 403 错误页面,而不是我重定向到的页面,而不是在本地的 IIS 上?

servlet发生异常时如何重定向到错误页面?

htaccess - 重定向到错误页面问题(带斜线或不带斜线)

php:如何重定向到带有错误消息的同一页面