【问题标题】:Python Flask app handle web and communicate using websockets to another appPython Flask 应用程序处理 web 并使用 websockets 与另一个应用程序通信
【发布时间】:2019-08-09 14:28:09
【问题描述】:

我正在构建一个应用程序:

  1. 处理网页请求(读/写数据库);

  2. 作为 websockets 客户端与其他系统进行通信(读/写 db);

我正在使用 Python Flask 框架。

有一些简单的应用程序服务网页,呈现模板 - 一切都很好。 实现了 SQLAlchemy 简单数据库 - 它非常适用于网页服务。

实现了 websockets 客户端与一些外部系统通信以查询一些信息并希望将这些信息存储到我的本地数据库中。

我将这个 websockets 客户端实现为单独的线程,以与外部系统进行异步通信。这个线程工作正常。

问题在于访问和使用数据库 - 当我尝试从 websockets 客户端线程使用数据库时,我收到错误“RuntimeError:在应用程序上下文之外工作”。或“RuntimeError:未找到应用程序。在视图函数中工作或推送应用程序上下文。”

请参阅下面的代码(简化)。我试图玩 app_context 但没有找到正确的方法。

也许我在同一个应用程序中使用 Flask Web 应用程序和 Websockets 客户端到外部系统的方法是个坏主意?我应该选择不同的方法吗?

大多数 Flask 应用程序和 Websockets 示例都是以网页和 websocket 协同工作的方式构建的。但在我的情况下,我需要 websockets 客户端与外部系统通信并将接收到的数据存储到同一数据库中,该数据库用于另一端的网页渲染。

class MyDataModel(db.Model):
  title = db.Column(db.String(80), unique=True, nullable=False, primary_key=True)

  def __repr__(self):
    return "<Title: {}>".format(self.title)

class WSClientThread(Thread):

  def on_message(ws, message):
    from flask import current_app
    # -----> PROBLEM HERE !!!
    with current_app.app_context():
      db.session.add(MyDataModel(title='AAA222'))
      db.session.commit()
    # <------ PROBLEM !!!

  def __init__(self):
    self.wsa = websocket.WebSocketApp('ws://IP:PORT', on_message=self.on_message)
    super(WSClientThread, self).__init__()

  def send(self, msg):
    self.wsa.send(msg)

  def run(self):
    self.wsa.run_forever()

创建 Flask 应用代码:

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)

    with app.app_context():
        db.init_app(app)

    wsc = WSClientThread()
    wsc.start()

    app.add_url_rule("/", endpoint="index")

    return app

数据库初始化代码:

db = SQLAlchemy()

def init_app(app):
    app.cli.add_command(init_db_command)
    db.init_app(app)

@click.command("init-db")
@with_appcontext
def init_db_command():
    init_db()

def init_db():
    db.drop_all()
    db.create_all()
    # test data insert - works OK
    db.session.add(MyDataModel(title='AAA'))
    db.session.commit()

【问题讨论】:

    标签: python sqlite flask websocket sqlalchemy


    【解决方案1】:

    这里的问题是如何从不同的线程访问同一个数据库。解决这个问题的方法是为这个单独的线程创建专用的数据库会话。

    是这样的:

      db_engine = create_engine(dburl, echo=False)
      DBSession = scoped_session(
        sessionmaker(
          autoflush=True,
          autocommit=False,
          bind=db_engine))
      DBSession.add(MyDataModel(title='AAA'))
      DBSession.commit()
    

    【讨论】:

      猜你喜欢
      • 2020-02-16
      • 1970-01-01
      • 2014-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-20
      • 1970-01-01
      相关资源
      最近更新 更多