Кнопка загрузки, перенаправляющая на неправильную страницу - PullRequest
0 голосов
/ 05 июля 2019

В моем проекте Django пользователь отправляет запрос Elasticsearch в форму и возвращает загружаемый отчет, сгенерированный из этого запроса. Мы внесли некоторые изменения, и теперь я пытаюсь заставить работать часть, возвращающую отчет. Тем не менее, я столкнулся с проблемой с моим шаблоном URL, который должен вызвать функцию представления для загрузки отчета.

У меня есть кнопка 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 icm_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 %}

1 Ответ

1 голос
/ 05 июля 2019

Ты делаешь это намного сложнее, чем нужно.

POST - это когда вы хотите отправить данные в бэкэнд, обычно для обновления чего-либо в базе данных, или в случае вашего представления get_query для создания файла.Однако в случае return_doc вы этого не делаете;Вы извлекаете что-то, что уже было создано, а именно файл.Таким образом, вы должны продолжать делать то, что вы делаете, что отправляет запрос GET.

Однако вы не отправляете имя файла, который хотите получить.В запросе GET это идет в конце URL в параметрах запроса - например, /mypath/?filename=myfilename.Так что просто используйте это в своем пути:

onclick="window.open('/return_doc/?filename={{fn}}')"

и в представлении:

fn = request.GET["filename"]

(Обратите внимание, однако, еще лучшим решением было бы создать ваш файл в каталоге мультимедиазатем он может быть доступен и обслуживаться сервером напрямую, без необходимости указывать URL-адрес или представление return_doc.)

...