为什么必须调用db.session.remove()?

时间:2016-09-14 00:40:43

标签: python session flask sqlalchemy flask-sqlalchemy

我正在学习烧瓶网络开发的教程,这是它的单元测试文件:

import unittest
from flask import current_app
from app import create_app, db

class BasicsTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app('testing')
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()

    def test_foo(self):
        pass

另外,我在SQLAlchemy document中找到了这些句子:

  

使用上述流程,整合Session的过程   Web应用程序有两个要求:

     
      
  • ...

  •   
  • 确保在Web请求结束时调用scoped_session.remove(),通常是通过与Web框架的事件系统集成到   建立“请求结束”事件。

  •   

我的问题是:为什么我需要拨打db.session.remove()

我认为只要不调用db.session.commit(),就不会修改数据库。此外,当我注释掉这一行时,应用程序仍然可以通过单元测试。

我已经查阅了Flask-SQLAlchemy和SQLAlchemy的文档,但前者甚至没有提到db.session.remove(),而后者太抽象了,我无法理解。

2 个答案:

答案 0 :(得分:11)

  

使用上述流程,将Session与Web应用程序集成的过程正好有两个要求:

     
      
  • ......
  •   
  • 确保在Web请求结束时调用scoped_session.remove(),通常是通过与Web框架的事件系统集成来建立“on request end”事件。
  •   

SQLAlchemy 中,提到了上述操作,因为Web应用程序中的会话应该作用域,这意味着每个请求处理程序都会创建并销毁自己的会话。

这是必要的,因为Web服务器可以是多线程的,因此可以同时提供多个请求,每个请求使用不同的数据库会话。

这种情况由 Flask-SQLAlchemy 精心处理,它为每个请求创建一个新的或新的范围会话。如果你进一步挖掘,你会发现here,它还会在app.teardown_appcontext(对于Flask> = 0.9),app.teardown_request(对于Flask 0.7-0.8),{{{ 1}}(对于Flask< 0.7),这里是调用app.after_request的地方。

测试环境并未完全复制实际请求的环境,因为它不会推送/弹出应用程序上下文。因此,在请求结束时永远不会删除会话。

作为旁注,请注意,当您致电db.session.remove()时,注册before_requestafter_request的功能也不会被调用。

您可以通过对测试进行少量更改来强制推送和弹出应用程序上下文,而不是手动推入client.get()并弹出setUp()

tearDown()

通过此更改,测试通过而无需手动编写def test_foo(self): with app.app_context(): client = app.test_client() # do testing here for your endpoints

Flask-Testing的文档似乎是错误的或更可能过时。也许事情就像他们在某些时候描述的那样,但对于当前的Flask和Flask-SQLAlchemy版本来说,这并不准确。

我希望这有帮助!

答案 1 :(得分:2)

在我检查整个项目之前,我不明白为什么db.session.remove()是必要的:

这是因为在config.py中,SQLALCHEMY_COMMIT_ON_TEARDOWN设置为True。因此,如果db.session未被销毁,则对db.session所做的更改将自动提交。