【问题标题】:How to automatically update text visualization?如何自动更新文本可视化?
【发布时间】:2021-07-11 23:43:02
【问题描述】:

我正在尝试构建一个烧瓶应用程序,让我可以可视化文本文件。

我可以打开文本文件并在我的 html 文件中使用它!

@app.route('/texts')
def texts():
with open("textfile.txt", "r") as f: 
    content = f.read() 
return render_template("texts.html", content=content)

在 HTML 中:

<div class="textzone">
  <pre>{{ content }}</pre> 
</div>

在 CSS 中:

.textzone {
overflow: scroll;
border: 3px solid #009688;
width: 330px;
background-color: rgb(231, 226, 226);
height:330px;
position: relative;
left: 125px;
top:80px;
-webkit-box-shadow: 11px 11px 10px 2px #262626; 
box-shadow: 11px 11px 10px 2px #262626;
padding: 20px;
}

当我更新文本文件时,只有刷新页面后才能在前端看到更新!

想问有没有什么办法不用刷新页面就能看到前端的变化

我想查看我对文本文件所做的更改,而无需刷新页面!

谢谢!

【问题讨论】:

  • @CypherX 据我了解,他说的是textfile.txt,而不是 Python 脚本。
  • @Felipe 我分享了@98​​7654322@ 让OP 使用textfile.txt 文件。
  • @Anis 当客户端向 Flask 发送请求时,服务器会响应一些 HTML 渲染(模板 + 用户上下文)并关闭连接。要从服务器端更新客户端,您需要一些额外的开销。您应该查看 Websockets(客户端/服务器之间的开放数据流)或来自客户端的定时请求(通过 HTML 中的 JS),以定期查询端点以获取更新。

标签: python html css flask


【解决方案1】:

有一些方法可以盗版 Flask,但不推荐。简而言之,Flask 对多线程没有很好的支持,并行执行是您的解决方案所需的要求之一(假设您计划以“更多”标准方式执行此操作)。

正如我在 cmets Flask 中提到的那样,仅凭自己无法完成您想做的事情。这是因为在典型的HTTP/1.1 事务(您的浏览器和 Flask 用于通信的协议)中不支持双向数据流。换句话说:当客户端向服务器发送请求时,Flask 将响应呈现的 HTML 页面,然后关闭连接。您需要让服务器保持与客户端的连接,并向客户端发送对textfile.txt 的任何更新。

要实现这一点,您需要在客户端和服务器端使用另一个协议,以及在服务器端使用异步代码执行

关于协议,这类事情的标准是Websocket。关于异步代码执行,这是 Flask 的一个问题:这个问题的要求之一是服务器需要 (1) 跟踪文本文件,以及 (2) 在更新时向客户端发送文本文件.用 Flask 做到这一点需要一些多线程,这对 Flask 不是很友好。因此,我实际上建议您研究类似FastAPI 的东西,它带有开箱即用的内置 Websocket,并且可以异步运行。

我还应该提到,您面临的问题相当独特,而且我个人从未见过适用的问题。我无法确认,但这看起来确实像 XY problem


例如,这里有一些代码可以使用 Flask、Flask-SocketIO (pip install flask-socketio) 和多线程来完成您正在寻找的工作。

请注意,Socket.IO 构建在 websocket 之上,并且客户端和服务器端都需要自己的支持代码。我不会详细说明为什么一个而不是另一个,但只需了解香草 Websocket 和 Socket.IO 在使用、应用程序等方面存在显着差异。另请注意,将threading 与 Flask 一起使用会导致必须处理的令人讨厌的未定义行为。自动重新加载之类的东西会中断并迫使您不断地重新加载应用程序。

再次:我无法充分表达我对 FastAPI 更好地解决这个问题的感觉(由于异步代码执行的能力),但为了直接回答您的问题,这里使用 Flask 实现了一个低于标准的实现:

from flask import Flask, render_template
from flask_socketio import SocketIO
from threading import Thread
from time import sleep

app = Flask(__name__)
io = SocketIO(app)


@app.route("/")
def index():
    return render_template("texts.html", content=get_file())


def get_file(loop=False, io=None):
    text = open("textfile.txt", "rb")

    def read():
        data = text.read()
        text.seek(0)
        return data

    old = read()
    while loop:

        current = read()
        if current != old:
            io.emit("text", read().decode("utf-8"), broadcast=True)
            old = current

        sleep(1)

    return text.read().decode("utf-8")


if __name__ == "__main__":
    Thread(target=lambda: get_file(loop=True, io=io)).start()
    io.run(app, debug=True)

在客户端你需要有:

<html>

<head>
    <style>
        .textzone {
            overflow: scroll;
            border: 3px solid #009688;
            width: 330px;
            background-color: rgb(231, 226, 226);
            height: 330px;
            position: relative;
            left: 125px;
            top: 80px;
            -webkit-box-shadow: 11px 11px 10px 2px #262626;
            box-shadow: 11px 11px 10px 2px #262626;
            padding: 20px;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
    <script type="text/javascript" charset="utf-8">
        console.log("running.");
        const socket = io('http://127.0.0.1:5000')

        socket.on('text', function(msg) {
            document.getElementById("content").innerHTML = msg;
        });
    </script>
</head>

<body>
    <div class="textzone">
        <pre id="content">{{ content }}</pre> 
    </div>
</body>

</html>

【讨论】:

    【解决方案2】:

    大家好,感谢您的帮助! 我找到了解决问题的方法

    我使用了 AJAX !好吧,我将解释我的解决方案:

    我在我的烧瓶应用程序中添加了一个路由,每次我想更新时都会调用它:

    @app.route('/update_text', methods=['POST'])
    def updatetext():
    with open("textfile.txt", "r") as f: 
        content = f.read()
    return jsonify('', render_template('updated_text_module.html', x=content))
    

    然后我在我的 html 文件中使用 AJAX 来定义函数:

    <script   src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    
    <script>
    
    $(function(){
        window.setInterval(function(){
         loadNewText()
      },9999)
    
    
    function loadNewText(){
      $.ajax({
        url:"/update_text",
        type: "POST",
        dataType: "json",
        success: function(data){
            $(new_text).replaceWith(data)
        }
    
       });
      }
     });
    
     </script>
    

    我使用了另一个模板来存储更新的文本:

    <div id="new_text" class="textzone">
     {{ x }}
    </div>
    

    这是我的问题的解决方案!谢谢大家的帮助 如果有人需要进一步的解释,我会回答你的 cmets !

    【讨论】:

    • 如果它对您有用,请关闭案例 - 很高兴您找到了解决方案。请务必点击帖子旁边的复选标记,将此问题标记为已回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2015-01-18
    相关资源
    最近更新 更多