V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
RicardoY
V2EX  ›  Python

flask 应该在__init__.py 里初始化数据库连接吗?

  •  1
     
  •   RicardoY · 2019-03-19 19:12:41 +08:00 · 3966 次点击
    这是一个创建于 2068 天前的主题,其中的信息可能已经有所发展或是发生改变。
    用 flask 做了个小东西,因为只想开一个数据库连接,所以在 __init__.py 里初始化,程序可以运行但是 pycharm 会提示 Unresolved reference。如果这样做是不正确的话...正确的做法是怎么样的呢
    17 条回复    2019-03-22 13:53:30 +08:00
    jinksw
        1
    jinksw  
       2019-03-19 19:15:54 +08:00
    from flask import g

    def get_db():
    if 'db' not in g:
    g.db = connect_to_database()

    return g.db

    @app.teardown_appcontext
    def teardown_db():
    db = g.pop('db', None)

    if db is not None:
    db.close()

    大概是这样吧?
    jinksw
        2
    jinksw  
       2019-03-19 19:16:29 +08:00   ❤️ 1
    http://flask.pocoo.org/docs/1.0/appcontext/
    参考 Storing Data 那一节
    RicardoY
        3
    RicardoY  
    OP
       2019-03-19 19:23:52 +08:00
    谢谢您 我去看看
    yushenglin
        4
    yushenglin  
       2019-03-19 20:39:30 +08:00
    最好一开始就模块化解耦,专门配置一个 settings 文件,里面写连接数据库,而且你可以用 sqlalchemy,连接数据库挺好用的
    RicardoY
        5
    RicardoY  
    OP
       2019-03-19 21:22:34 +08:00
    @yushenglin 我有一个 settings 文件,但是里面只放了数据库的连接信息。如果我在 settings 里连接数据库的话,是在每个用到数据库连接的地方都 import 这个文件吗?
    megachweng
        6
    megachweng  
       2019-03-19 21:39:29 +08:00 via iPhone
    secsilm
        7
    secsilm  
       2019-03-19 21:43:43 +08:00 via Android
    前段时间刚查过,国外大神们意见都不一致。。。
    corvofeng
        8
    corvofeng  
       2019-03-19 22:16:29 +08:00 via Android
    我是小菜🐔, 不过我不喜欢在__init__.py 里面写东西。 主要原因是在单元测试的时候, 有可能会执行我控制不了的语句
    enrolls
        9
    enrolls  
       2019-03-19 22:56:57 +08:00
    使用 @app.before_request 和 @app.teardown_request
    装饰器下的函数,在 before_request 设置 _app_ctx_stack.top.db= sqlalchemy.orm.scoped_session()
    在 teardown_request 的时候 _app_ctx_stack.top.db.remove()
    zxcvsh
        10
    zxcvsh  
       2019-03-19 23:51:30 +08:00 via iPhone
    搜索:flask 数据库链接持久化
    你会看到 #1 #9 相关的东西
    RicardoY
        11
    RicardoY  
    OP
       2019-03-20 09:42:34 +08:00 via Android
    @enrolls 谢谢
    RicardoY
        12
    RicardoY  
    OP
       2019-03-20 09:48:41 +08:00 via Android
    @zxcvsh 用这个作为关键词搜索出来的内容大多都是 ORM 框架的相关信息
    TrickWu
        13
    TrickWu  
       2019-03-20 10:05:30 +08:00
    我用的是 flask_sqlalchemy
    数据库配置写在 config.py 里面

    __init__.py 里面

    db = SQLAlchemy()

    def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config_name)
    db.init_app(app)
    return app

    然后再主程序里面启动
    app = create_app("app.config")
    app.run()

    大致这样,不过这样有个缺点,就是查询数据库的时候只能在请求上下文中
    zxcvsh
        14
    zxcvsh  
       2019-03-20 10:09:29 +08:00 via iPhone
    @RicardoY ...这返回差异太大了
    那你换成 链接池 或 flask g 对象看看
    enrolls
        15
    enrolls  
       2019-03-20 11:53:44 +08:00
    因此,初始化数据库连接应该在哪里。
    笼统地讲,哪里都可以,看怎么组织代码。关键在于实例化 Flask() 后,在某个 py 文件里面,import 实例,写 2 个函数,把装饰器带上。
    有多个函数需要注册,可以按顺序写在一个函数里面,或者看看 before_request_funcs。
    teardown_request 同理。
    RicardoY
        16
    RicardoY  
    OP
       2019-03-20 12:28:06 +08:00
    @megachweng 这个真的很有用..!
    yuchenyang1994
        17
    yuchenyang1994  
       2019-03-22 13:53:30 +08:00
    都说的不太好,g 对象虽然可以,但是不符合 flask 的约定,虽然 flask 对这块管的毕竟宽松,但是使用扩展的约定其实是最好的
    example:
    ```python
    class Sqlite:
    def __init__(self):
    def __init__(self, app=None):
    self.app = app
    if app is not None:
    self.init_app(app)

    def init_app(self, app):
    app.config.setdefault('SQLITE3_DATABASE', ':memory:')
    app.teardown_appcontext(self.teardown)

    def connect(self):
    return sqlite3.connect(current_app.config['SQLITE3_DATABASE'])

    def teardown(self, exception):
    ctx = _app_ctx_stack.top
    if hasattr(ctx, 'sqlite3_db'):
    ctx.sqlite3_db.close()

    @property
    def connection(self):
    ctx = _app_ctx_stack.top
    if ctx is not None:
    if not hasattr(ctx, 'sqlite3_db'):
    ctx.sqlite3_db = self.connect()
    return ctx.sqlite3_db

    ```
    这里的 teardown 函数就是 flask 的应用情境的上下文,也就是说,在请求后关闭 sqlite
    当然,如果在请求外的时候则:
    ```python
    with app.app_context():
    cur = db.connection.cursor()
    cur.execute(...)
    ```
    这样的好处就是在请求环境下你可以直接 import 你的 Sqlite 对象用,不需要 request.g.sqllite,初始化也是符合约定
    ```python
    db = Sqlite()
    app.init_app(db)
    # OR
    db = Sqlite(app)
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2593 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 01:45 · PVG 09:45 · LAX 17:45 · JFK 20:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.