SQLAlchemy仍然能够在删除后从会话中获取对象

bra*_*nks 0 python sqlalchemy flask

我有一个端点从我的数据库中删除一个对象.我用以下代码删除它:

my_object = Object.query.get(id)
db.session.delete(my_object)
db.session.commit()
return json.dumps({'success': True}
Run Code Online (Sandbox Code Playgroud)

我有一个API测试来测试我创建对象的端点,然后使用端点将其删除.我试图断言删除后发生它不在数据库中.

my_object = MyObject()
db.session.add(my_object)
db.session.commit()
response = requests.delete('{}/my-object/{}'.format(
    os.environ.get('MY_URL'),
    my_object.id
))
self.assertTrue(response.json()['success']) // this passes
self.assertEqual(200, response.status_code) // this passes
result = db.session.query(MyObject).get(my_object.id)
print(result.id) // prints the id of the job even though it is deleted from the database
Run Code Online (Sandbox Code Playgroud)

我认为这与一些SQLAlchemy会话缓存有关.我试过了db.session.flush(),但db.session.expire_all()没有用.该对象实际上正在从数据库中删除.所以我希望查询结果是None.

我在文档中看到了这一点,但没有完全包裹我的脑袋.何时提交和关闭会话

谢谢你的帮助.

Iai*_*can 5

因此,在您的测试代码中,您将对象添加到会话并提交它.它会保存到数据库中,并且是会话的标识映射.

然后你点击你的应用程序,它有自己的会话.它会删除对象并提交,现在它已从数据库中删除了.但...

您之前的会话对此一无所知,当您使用.get()时,它将返回其身份映射中的内容:带有ID的Python对象.除非你关闭会话或强制刷新数据库,否则它不会重新获取(我不记得OTOH如何做到这一点,但你可以,它在某个地方的文档中).如果你使用了一个干净的第三个会话,它将有一个新的身份映射,并且不会持有对python对象的引用,所以你得到你期望的,即.没有结果.这是设计原因,因为Identity Map允许SQLAlchemy将一堆更改链接到一个最佳SQL查询中,该查询仅在您提交时触发.

所以,是的,你看到身份地图中的取物仍然存在.(你甚至可以在交互式解释器中打开它并且四处寻找)它是有道理的,因为你说有两个不同web请求的线程,另一个是在另一个请求删除对象时用一个对象做一些更长寿的东西.第一个线程不应该在使用该对象的Python代码上进行barf,因为这只会在代码中的任何地方触发随机异常.它应该只是认为它可以做它的事情,然后在提交时失败,触发回滚.

HTH