python - 无法重定向到 flask 中的网址

标签 python flask

我无法重定向到 main.demo。一切正常,直到重定向后没有发生数据上传。为什么?

编辑:app.py

from flask import Blueprint
main = Blueprint('main', __name__)
import json
import os
from flask import Flask, request,render_template,url_for,redirect
from werkzeug import secure_filename

import glob2
from uuid import uuid4



@main.route('/')
def index():
    """Main index page """
    return render_template('index.html')

@main.route('/upload', methods=["GET","POST"])
def upload():
    if request.method == 'POST':
        form = request.form
        # Create a unique "session ID" for this particular batch of uploads.
        upload_key = str(uuid4())

        # Is the upload using Ajax, or a direct POST by the form?
        is_ajax = False
        if form.get("__ajax", None) == "true":
            is_ajax = True

        # Target folder for these uploads.
        target = "upload/{}".format(upload_key)
        try:
            os.mkdir(target)
        except:
            if is_ajax:
                return ajax_response(False, "Couldn't create upload directory: {}".format(target))
            else:
                return "Couldn't create upload directory: {}".format(target)

        print "=== Form Data ==="
        for key, value in form.items():
            print key, "=>", value

        for upload in request.files.getlist("file"):
            filename = upload.filename.rsplit("/")[0]
            destination = "/".join([target, filename])
            print "Accept incoming file:", filename
            print "Save it to:", destination
            upload.save(destination)
        return redirect(url_for("main.demo"))
    return render_template("upload.html")


@main.route('/demo',methods=["GET","POST"])
def demo():
    if request.method == "GET":
       return render_template("demo.html")

def ajax_response(status, msg):
    status_code = "ok" if status else "error"
    return json.dumps(dict(
        status=status_code,
        msg=msg,
    ))

def create_app():
    global app
    app = Flask(__name__,template_folder=os.path.join(os.path.dirname(os.path.abspath(__file__)),'templates'))
    app.debug = True
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    app.register_blueprint(main)
    #app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
    return app

以下是我收到的一些日志:

=== Form Data ===
__ajax => true
Accept incoming file: demo.txt
Save it to: upload/XXXXXXX-XXXXXX-XXXXX-XXXXXXX/demo.txt
"POST /upload HTTP/1.1" 302 231 "http://localhost:5000/upload" 

"GET /demo HTTP/1.1" 200 3624 "http://localhost:5000/upload" 

它显示它正在进行演示,但最终的网址是错误的。为什么会这样?

编辑1:

我是否因为页面没有刷新而无法提交表单?但它被重定向到 demo() 函数执行它,但不执行 render_template。或者它确实如此,但不知何故又回到了相同的功能?

编辑2:

添加此代码的更多内容是在后台使用以下JavaScript

// Constants
var MAX_UPLOAD_FILE_SIZE = 1024*1024; // 1 MB
var UPLOAD_URL = "/upload";
var NEXT_URL   = "/demo";

// List of pending files to handle when the Upload button is finally clicked.
var PENDING_FILES  = [];


$(document).ready(function() {
    // Set up the drag/drop zone.
    initDropbox();

    // Set up the handler for the file input box.
    $("#file-picker").on("change", function() {
        handleFiles(this.files);
    });

    // Handle the submit button.
    $("#upload-button").on("click", function(e) {
        // If the user has JS disabled, none of this code is running but the
        // file multi-upload input box should still work. In this case they'll
        // just POST to the upload endpoint directly. However, with JS we'll do
        // the POST using ajax and then redirect them ourself when done.
        e.preventDefault();
        doUpload();
    })
});


function doUpload() {
    $("#progress").show();
    var $progressBar   = $("#progress-bar");

    // Gray out the form.
    $("#upload-form :input").attr("disabled", "disabled");

    // Initialize the progress bar.
    $progressBar.css({"width": "0%"});

    // Collect the form data.
    fd = collectFormData();

    // Attach the files.
    for (var i = 0, ie = PENDING_FILES.length; i < ie; i++) {
        // Collect the other form data.
        fd.append("file", PENDING_FILES[i]);
    }

    // Inform the back-end that we're doing this over ajax.
    fd.append("__ajax", "true");

    var xhr = $.ajax({
        xhr: function() {
            var xhrobj = $.ajaxSettings.xhr();
            if (xhrobj.upload) {
                xhrobj.upload.addEventListener("progress", function(event) {
                    var percent = 0;
                    var position = event.loaded || event.position;
                    var total    = event.total;
                    if (event.lengthComputable) {
                        percent = Math.ceil(position / total * 100);
                    }

                    // Set the progress bar.
                    $progressBar.css({"width": percent + "%"});
                    $progressBar.text(percent + "%");
                }, false)
            }
            return xhrobj;
        },
        url: UPLOAD_URL,
        method: "POST",
        contentType: false,
        processData: false,
        cache: false,
        data: fd,
        success: function(data) {
            $progressBar.css({"width": "100%"});
            data = JSON.parse(data);

            // How'd it go?
            if (data.status === "error") {
                // Uh-oh.
                window.alert(data.msg);
                $("#upload-form :input").removeAttr("disabled");
                return;
            }
            else {
                // Ok! Get the UUID.
                var uuid = data.msg;
                //window.location = NEXT_URL + uuid;
                window.location = NEXT_URL;
            }
        },
    });
}


function collectFormData() {
    // Go through all the form fields and collect their names/values.
    var fd = new FormData();

    $("#upload-form :input").each(function() {
        var $this = $(this);
        var name  = $this.attr("name");
        var type  = $this.attr("type") || "";
        var value = $this.val();

        // No name = no care.
        if (name === undefined) {
            return;
        }

        // Skip the file upload box for now.
        if (type === "file") {
            return;
        }

        // Checkboxes? Only add their value if they're checked.
        if (type === "checkbox" || type === "radio") {
            if (!$this.is(":checked")) {
                return;
            }
        }

        fd.append(name, value);
    });

    return fd;
}


function handleFiles(files) {
    // Add them to the pending files list.
    for (var i = 0, ie = files.length; i < ie; i++) {
        PENDING_FILES.push(files[i]);
    }
}


function initDropbox() {
    var $dropbox = $("#dropbox");

    // On drag enter...
    $dropbox.on("dragenter", function(e) {
        e.stopPropagation();
        e.preventDefault();
        $(this).addClass("active");
    });

    // On drag over...
    $dropbox.on("dragover", function(e) {
        e.stopPropagation();
        e.preventDefault();
    });

    // On drop...
    $dropbox.on("drop", function(e) {
        e.preventDefault();
        $(this).removeClass("active");

        // Get the files.
        var files = e.originalEvent.dataTransfer.files;
        handleFiles(files);

        // Update the display to acknowledge the number of pending files.
        $dropbox.text(PENDING_FILES.length + " files ready for upload!");
    });

    // If the files are dropped outside of the drop zone, the browser will
    // redirect to show the files in the window. To avoid that we can prevent
    // the 'drop' event on the document.
    function stopDefault(e) {
        e.stopPropagation();
        e.preventDefault();
    }
    $(document).on("dragenter", stopDefault);
    $(document).on("dragover", stopDefault);
    $(document).on("drop", stopDefault);
}

我尝试从以下链接集成功能:Flask Multiple Upload

无法理解为什么即使在点击/demo后它仍然会/upload

有人可以帮我解决后台发生的事情吗?

最佳答案

简而言之,我的猜测是您错误地期望对 XHR 请求的响应来更改浏览器地址。

以下是我认为正在发生的事情的更详细解释:

  1. 用户点击上传按钮
  2. doUpload() 调用 Javascript 函数
  3. doUpload() 向 UPLOAD_URL 发出 XHR (ajax) 请求 (POST/upload)
  4. upload() 调用 Python 函数,成功上传后生成一个指向 /demo 的“302 Found”重定向响应
  5. 浏览器收到此响应并遵循提供的 URL,在本例中,它将转到 /demo (请注意,这不会更改地址,它作为 XHR 请求的一部分在后台发生)
  6. demo() Python 函数呈现一些 HTML,该 HTML 作为“200 OK”响应返回
  7. 第 3 步中的 XHR 调用接收第 5 步中的此 HTML,并检查响应是否指示成功
  8. success 函数被触发,并尝试将 HTML 解析为 JSON JSON.parse(data),这应该会失败

我对您的浏览器、Javascript 库、HTML 模板和用户交互做了一些假设,但我认为这是您提供的代码中最有可能的解释。

我的建议是首先尝试用这样的内容替换return redirect(url_for("main.demo")):

if is_ajax:
    return ajax_response(True, upload_key)
else:
    return redirect(url_for("main.demo"))

在这种情况下,成功上传后,window.location = NEXT_URL 将在您的 doUpload() 内执行,这将更改您浏览器中的地址。

关于python - 无法重定向到 flask 中的网址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35794102/

相关文章:

python - Flask 应用程序内存泄漏与 sql 炼金术

python - 使用 DictWriter 更改列标题

python - GStreamer;无法播放错误: "Invalid URI\"\"."

mongodb - 无法运行 docker flask image -pymongo.errors.ServerSelectionTimeoutError : localhost:27017: [Errno 111] Connection refused

python - 你怎么能得到 flask 中文件的文件路径?

python - 导入错误 : No module named app

python - 使用 matplotlib 在 sccatterplot 中创建置信椭圆

python - Django:从元组中获取首选值

具有关联扩展名的 Python 可执行运行文件

python - Flask-marshmallow base_fields.base_fields.Nested 中的函数