V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
woshichuanqilz
V2EX  ›  Flask

flask 的 render_template 页面刷新的问题?

  •  
  •   woshichuanqilz · 2018-03-14 19:00:40 +08:00 · 8749 次点击
    这是一个创建于 2206 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我用一个页面显示一个文件夹下面的所有文件, 页面上有上传和删除的方法, 上传的方法 ok, 主要就是提交之后, 使用 redirect, 这个时候新上传的文件会直接显示出来, return redirect(url_for('show_user_file', username=session['cur_username']))

    但是问题出现在删除的时候, 使用的代码依然是, return redirect(url_for('show_user_file', username=session['cur_username'])) 但是这个时候文件不会减少, 就是虽然删除了, 文件还是显示在页面上.

    我调试了一下, show_user_filereturn render_template('listfile.html', files=file_dict, used_space = used_space) 的参数里面, file_dict 是存储当前文件夹里面的文件的参数, 这个 file_dict 的内容是 ok 的, 也就是说这里面已经没有了那个被删除的文件, 但是页面上还有, 只有刷新一下这个删除的文件才会删除掉。

    开始想在页面的里面直接用 JavaScript 删除掉这个文件, 但是也可能出现服务端删除失败的情况, 所以不想用这个方法。

    请问这个问题如何解决, 删除文件后为什么 render 之后的页面没有更新?

    我开始猜测是 post 之后更新页面, 但是不是修改了之后还是没有变请问是怎么回事?

    删除:

    @app.route('/delfile', methods=['GET', 'POST'])
    def delfile():
        print('in delfile')
        if request.method == 'GET':
            filename = re.sub("_btn$", "", request.args.get('filename'))
            file_path = os.path.join(session['cur_username'], filename)
            if os.path.exists(file_path):
               os.remove(file_path)
    
        return redirect(url_for('show_user_file', username=session['cur_username']))
    
    
    

    上传

    @app.route('/upload/<username>', methods=['GET', 'POST'])
    def show_user_file(username):
        file_path = username
        if not os.path.exists(file_path):
            os.makedirs(file_path)
    
        BASE_DIR = '.'
        req_path = username
    
        # Joining the base and the requested path
        abs_path = os.path.join(BASE_DIR, req_path)
    
        # Return 404 if path doesn't exist
        if not os.path.exists(abs_path):
            return abort(404)
    
        # Check if path is a file and serve
        if os.path.isfile(abs_path):
            return send_file(abs_path)
    
        if request.method == 'POST':
            file = request.files['file']
            if file:
                # filename = secure_filename(file.filename)
                filename = file.filename
                file.save(os.path.join(file_path, filename))
                return redirect(url_for('show_user_file', username=session['cur_username']))
        files = os.listdir(abs_path)
        file_dict={}
        for i in files:
            file_dict[i] = os.path.join(abs_path, i)
    
        used_space = get_size(abs_path)
    
        return render_template('listfile.html', files=file_dict, used_space = used_space)
    
    

    show_user_file:

    # Show User Folder 
    @app.route('/upload/<username>', methods=['GET', 'POST'])
    def show_user_file(username):
        file_path = username
        if not os.path.exists(file_path):
            os.makedirs(file_path)
    
        BASE_DIR = '.'
        req_path = username
    
        # Joining the base and the requested path
        abs_path = os.path.join(BASE_DIR, req_path)
    
        # Return 404 if path doesn't exist
        if not os.path.exists(abs_path):
            return abort(404)
    
        # Check if path is a file and serve
        if os.path.isfile(abs_path):
            return send_file(abs_path)
    
        if request.method == 'POST':
            file = request.files['file']
            if file:
                # filename = secure_filename(file.filename)
                filename = file.filename
                file.save(os.path.join(file_path, filename))
                return redirect(url_for('show_user_file', username=session['cur_username']))
        files = os.listdir(abs_path)
        file_dict={}
        for i in files:
            file_dict[i] = os.path.join(abs_path, i)
    
        used_space = get_size(abs_path)
    
        return render_template('listfile.html', files=file_dict, used_space = used_space)
    
    
    
    第 1 条附言  ·  2018-03-15 14:23:29 +08:00
    现在的问题是页面的源码已经变化了, 但是页面没有刷新, 这个是什么问题?
    13 条回复    2018-03-15 14:52:06 +08:00
    justinwu
        1
    justinwu  
       2018-03-14 21:34:49 +08:00   ❤️ 1
    啥原因我也不知道,但是先说说你设计上的一些问题,路子走对了,再调问题吧:

    一般都是 Post/Redirect/Get 模式,你删除文件却是 Get/Redirect/Get 模式。对服务端数据有修改的操作请不要用 GET。你那个 delfile 就该用 POST。

    你的 show_user_file action 怎么对应的又是 /upload url,怪怪的。
    下面这样才对头啊,各函数各司其职:

    @app.route('/delfile', methods=['POST'])
    def delfile():

    @app.route('/upload/<username>', methods=['POST'])
    def upload_file(username):

    @app.route('/listfiles/<username>', methods=['GET'])
    def show_user_file(username):

    另外,url 里面不要搞 username 吧,你难道要一个用户操作另一个用户的文件?如果不是,默默用 session 里面的就完了。
    geek123
        2
    geek123  
       2018-03-14 21:43:57 +08:00   ❤️ 1
    重定向响应
    使用 flask 框架的 redirect()方法,可以要求客户端进行重定向:

    flask.redirect(location, code=302, Response=None)
    redirect()方法其实是构造了一个具有重定向状态码的 Response 对象。重定向状态码 默认为 302,这表示一个临时性重定向。redirect()方法还支持以下重定向状态码:

    301 - 请求的网页已被永久移动到新位置
    302 - 服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
    303 - 对于 POST 请求,它表示请求已经被处理,客户端可以接着使用 GET 方法去请求 Location 里的 URI
    305 - 请求者只能使用代理访问请求的网页。
    307 - 对于 POST 请求,表示请求还没有被处理,客户端应该向 Location 里的 URI 重新发起 POST 请求


    你指定一下重定向码试试
    woshichuanqilz
        3
    woshichuanqilz  
    OP
       2018-03-15 10:46:17 +08:00
    @justinwu 非常感谢详尽的回答, 十分感谢, 受益匪浅。

    1. delfile 中的 post 已经修改
    2. 函数名和 url 的匹配已经修改

    ```
    #del file
    @app.route('/delfile', methods=['GET', 'POST'])
    def delfile():
    print('in delfile')
    if 'logged_in' not in session or not session['logged_in']:
    return '用户未登录或者访问权限不够'

    if request.method == 'POST':
    # filename = re.sub("_btn$", "", request.args.get('filename'))
    filename = re.sub("_btn$", "", request.form['filename'])
    file_path = os.path.join(session['cur_username'], filename)
    if os.path.exists(file_path):
    os.remove(file_path)

    file_dict, used_space = get_file_info(session['cur_username'])
    return render_template('listfile.html', files=file_dict, used_space = used_space)


    ```

    ```
    @app.route('/show_user_file', methods=['GET', 'POST'])
    def show_user_file():

    if 'logged_in' not in session or not session['logged_in']:
    return '用户未登录或者访问权限不够'

    file_path = session['cur_username']
    username = session['cur_username']
    if not os.path.exists(file_path):
    os.makedirs(file_path)

    if request.method == 'POST':
    file = request.files['file']
    if file:
    # filename = secure_filename(file.filename)
    filename = file.filename
    file.save(os.path.join(file_path, filename))
    return redirect(url_for('show_user_file'))

    file_dict, used_space = get_file_info(username)
    return render_template('listfile.html', files=file_dict, used_space = used_space)

    ```

    ```
    def get_file_info(username):
    BASE_DIR = '.'
    req_path = username
    file_path = username

    # Joining the base and the requested path
    abs_path = os.path.join(BASE_DIR, req_path)

    # Return 404 if path doesn't exist
    if not os.path.exists(abs_path):
    return abort(404)

    # Check if path is a file and serve
    if os.path.isfile(abs_path):
    return send_file(abs_path)

    files = os.listdir(abs_path)
    file_dict={}
    for i in files:
    file_dict[i] = os.path.join(abs_path, i)

    used_space = get_size(abs_path)
    return file_dict, used_space

    ```




    ![20180315100643]( http://7xpvdr.com1.z0.glb.clouddn.com/680c2fc1-aab5-4f11-bb3b-28b772d229cb0315100557.png)


    这个是我的实操的效果图, 点击删除按钮, file_dict 已经变成空了, 但是 render_template 的网页没有刷新

    ![20180315104614]( http://7xpvdr.com1.z0.glb.clouddn.com/ea205440-58b0-4024-80d3-990ca41057ce0315104524.png)
    woshichuanqilz
        4
    woshichuanqilz  
    OP
       2018-03-15 10:47:08 +08:00
    @geek123 研究了一下没太看懂这些状态码, 那个能适用于我现在的这个情况。 谢谢~
    woshichuanqilz
        5
    woshichuanqilz  
    OP
       2018-03-15 10:47:50 +08:00
    ```
    @app.route('/delfile', methods=['GET', 'POST'])
    def delfile():
    print('in delfile')
    if 'logged_in' not in session or not session['logged_in']:
    return '用户未登录或者访问权限不够'

    if request.method == 'POST':
    # filename = re.sub("_btn$", "", request.args.get('filename'))
    filename = re.sub("_btn$", "", request.form['filename'])
    file_path = os.path.join(session['cur_username'], filename)
    if os.path.exists(file_path):
    os.remove(file_path)

    file_dict, used_space = get_file_info(session['cur_username'])
    print('file_dict:')
    print(file_dict)
    return redirect(url_for('show_user_file'))
    ```

    delfile 修改成返回 redirect 还是不行。
    justinwu
        6
    justinwu  
       2018-03-15 11:07:53 +08:00 via iPhone   ❤️ 1
    @woshichuanqilz 不用在 delfile 里面打印 file list dict,应该在 show user file 里面,看看 redirect 后请求到底来了没,状态到底对不对
    woshichuanqilz
        7
    woshichuanqilz  
    OP
       2018-03-15 11:14:18 +08:00
    @justinwu show_use file 里面也是空的
    我看了一下源代码, 源代码是没有问题的, 就是说如果你点击删除之后, 查看源代码确实是对的已经更新了, 但是表现在页面上没有更新。
    justinwu
        8
    justinwu  
       2018-03-15 11:58:36 +08:00 via iPhone   ❤️ 1
    @woshichuanqilz

    打 server 请求 log 都打开,看看 del file 后有没有请求文件列表页面;
    换不同浏览器试试看; chrome 开发者工具 network 调试;看看浏览器请求对不对;
    redirect 强制加一个 query string,搞点随机数时间戳都行,如 /listfile?hd23dd ;
    fiddler 工具分析整个 http 交互,看看有无异常;

    顺藤摸瓜,总能找到哪里不对
    woshichuanqilz
        9
    woshichuanqilz  
    OP
       2018-03-15 14:21:47 +08:00
    @justinwu
    1. 确定是请求了, 不然页面的源代码不会变化,
    2. 换了火狐浏览器没有区别
    3. chrome network 显示这个页面被请求过了 ![20180315141828]( http://7xpvdr.com1.z0.glb.clouddn.com/f3243b26-fa88-4962-a349-82c143fe23e70315141755.png)

    4. 没明白那个 redirect 加参数是什么意思。
    5. 用了 fiddler 确实很强大, 这里面是正常的删除文件后的页面已经返回了
    ![20180315142044]( http://7xpvdr.com1.z0.glb.clouddn.com/b5b3ed71-7759-4913-8567-8f641b426b0b0315141925.png)

    现在的问题是网页的源码都变了, 但是页面没有刷新。

    我在 listfile 里面删除按钮绑定的是这个函数, 不知道处理有没有问题。

    ```
    <script>
    function sendfilename() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "/delfile", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send("filename=" + event.target.id);
    }
    </script>

    ```
    woshichuanqilz
        10
    woshichuanqilz  
    OP
       2018-03-15 14:30:23 +08:00
    在 chrome network 里面 disable cache 也没用。 我以为是缓存的问题
    justinwu
        11
    justinwu  
       2018-03-15 14:45:47 +08:00   ❤️ 2
    @woshichuanqilz 你那个 sendfilename 的函数不对吧,只是发送请求,但是没有处理响应,没有让当前页面 refresh 或是 update 啊。

    给一段我珍藏多年的表单 POST 代码,立马解决问题:
    <script>
    function post(path, params, method) {
    method = method || "post"; // Set method to post by default if not specified.

    // The rest of this code assumes you are not using a library.
    // It can be made less wordy if you use one.
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", path);

    for(var key in params) {
    if(params.hasOwnProperty(key)) {
    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("type", "hidden");
    hiddenField.setAttribute("name", key);
    hiddenField.setAttribute("value", params[key]);

    form.appendChild(hiddenField);
    }
    }

    document.body.appendChild(form);
    form.submit();
    }

    //按钮 call 这个函数,跟据你上面的代码来的:
    function deleteFile(filename)
    {
    post("/delfile", { filename: filename });
    }
    </script>
    woshichuanqilz
        12
    woshichuanqilz  
    OP
       2018-03-15 14:49:13 +08:00
    用一个 settimerout 在点击后 refresh 页面算是暂时解决了。。。 但是还是不知道原因。
    woshichuanqilz
        13
    woshichuanqilz  
    OP
       2018-03-15 14:52:06 +08:00
    @justinwu 这个 post 屌爆了。。。 真的是谢谢你的帮忙了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4144 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 10:12 · PVG 18:12 · LAX 03:12 · JFK 06:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.