无法重定向到烧瓶中的网址

时间:2016-03-04 10:49:36

标签: 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

无法理解为什么即使在点击/upload

之后它仍然会/demo

有人可以帮我解决背景中发生的事情吗?

1 个答案:

答案 0 :(得分:2)

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

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

  1. 用户点击上传按钮
  2. doUpload()调用Javascript函数
  3. doUpload()向UPLOAD_URL(POST /upload)发出XHR(ajax)请求
  4. upload()调用Python函数,成功上传后会生成“302 Found”重定向响应 / demo
  5. 浏览器收到此响应并按照提供的URL进行操作,在这种情况下,它会转到 / demo (请注意,这不会更改地址,它会在后台作为XHR请求的一部分发生)
  6. demo() Python函数呈现一些HTML,它作为“200 OK”响应返回
  7. 来自步骤3的XHR调用从步骤5接收此HTML并检查响应是否表示成功
  8. success函数被触发并尝试将HTML解析为JSON JSON.parse(data),这将失败
  9. 我对您的浏览器,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()内执行,这将更改浏览器中的地址。