Flask中使用SQLAlchemy时drop_all()冻结

40 投票
4 回答
18636 浏览
提问于 2025-04-18 10:14

我正在为一个Flask应用写测试用例。

我有一个叫做setUp的方法,它会在重新创建数据库表之前先删除这些表。它的代码大概是这样的:

def setUp(self):
    # other stuff...
    myapp.db.drop_all()
    myapp.db.create_all()
    # db creation...

这个方法在第一次测试时运行得很好,但在第二次测试开始之前,它在drop_all这一步卡住了。

编辑:当我中断这个过程时,堆栈跟踪信息是这样的:

  File "populate.py", line 70, in create_test_db
    print (myapp.db.drop_all())
  File ".../flask_sqlalchemy/__init__.py", line 864, in drop_all
    self._execute_for_all_tables(app, bind, 'drop_all')
  File ".../flask_sqlalchemy/__init__.py", line 848, in _execute_for_all_tables
    op(bind=self.get_engine(app, bind), tables=tables)
  File ".../sqlalchemy/sql/schema.py", line 3335, in drop_all
  ....
  File "/Library/Python/2.7/site-packages/MySQLdb/cursors.py", line 190, in execute
    r = self._query(query)

有没有人知道怎么解决这个问题?

4 个回答

1

我之前也遇到过同样的问题。在我的情况中,有两个不同的会话同时对同一张表进行查询。我的解决办法是为这两个地方使用一个共享的会话。

我在一个不同的模块中创建了这个会话,这样就避免了循环依赖的问题,代码如下:

db.py:

from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()

models.py:

from .db import db
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)

app.py:

from flask import Flask
from .db import db
app = Flask(__name__)
db.init_app(app)

在你的代码中只使用 db.session,这样可以确保你在同一个会话里。在测试时,记得在清理时执行回滚操作。

5

我是一个Flask开发者,正在使用flask_sqlalchemy和pytest来测试我的应用服务器。当我运行命令 db.drop_all() 时,控制台显示我的一个表被锁住了。

在运行 db.drop_all() 之前,我使用 db.session.remove() 来清除会话。

30

只需要在你的应用里关闭所有的会话,然后再调用 drop_all

    def __init__(self, conn_str):
        self.engine = create_engine(conn_str)
        self.session_factory = sessionmaker(engine)
        
    def drop_all(self):
        self.session_factory.close_all() # <- don't forget to close
        Base.metadata.drop_all(self._engine)

关于 SQLAlchemy 中会话的更多信息,可以查看这个链接: http://docs.sqlalchemy.org/en/latest/orm/session_api.html?highlight=close_all

45

好的,可能还有其他解决办法,但目前为止,我在网上查找后发现,如果我在代码前面加上一个 myapp.db.session.commit(),问题就解决了。我想,可能是某个地方的事务在等待提交。

def setUp(self):
    # other stuff...
    myapp.db.session.commit()   #<--- solution!
    myapp.db.drop_all()
    myapp.db.create_all()
    # db creation...

撰写回答