在烧瓶中正确使用SQLAlchemy

Jay*_*ton 2 python sqlalchemy flask

我正在使用flask和sqlalchemy制作用于娱乐的基本API。我在sqlalchemy文档中读到,您只能使用一个带有连接字符串的引擎。应该如何在app> __init__.py文件中构建结构?在运行以启动Flask服务器的Flask文件中?这是我的github存储库,因为我认为仅查看当前应用程序结构及其可能存在的任何缺陷就比较容易。https://github.com/JayHelton/Geekdom_Web_App

在我的查询方法中,我每次都在创建一个新的数据库引擎,并且似乎正在运行,但是如果多个人尝试调用这些方法,我不想遇到任何问题。谢谢!

Mes*_*ssa 7

当然,已经有Flask扩展Flask-SQLAlchemy -Flask的Flask文档SQLAlchemy中也提到了。但是,与大多数Flask扩展一样,它所做的只是将一些“管道” Flask和SQLAlchemy(或任何其他库)“一起”。最好的文档通常是源代码的时间:)

github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy/__init__.py

但是,在Flask-SQLAlchemy的情况下,这是很多代码,并且是有关范围会话与Flask上下文,修改跟踪和持续时间调试交织在一起的一些黑魔法,以及在Web应用程序中有用的所有东西以及所有可能的极端情况等。我会说这有点工程化。我并不是说您不应该使用它-只是从扩展代码乍一看SQLAlchemy和Flask之间的连接是不可见的,因此可能需要更多的阅读时间。

但是,如果您希望自己进行操作,这非常简单(嗯,就像SQLAlchemy所能做到的一样容易)-只需初始化SQLAlchemy,这样您就可以获得一个sessionmaker,然后在每个请求之前创建一个会话,然后别忘了在它之后关闭它request :),然后在Flask处理程序中使用此会话(我的意思是@app.route函数)。

import flask
import sqlalchemy
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class Item (Base):

    __tablename__ = 'items'

    id = Column(Integer, primary_key=True)
    title = Column(String)    

engine = sqlalchemy.create_engine('sqlite:///bestappever.db', echo=True)
Session = sessionmaker(bind=engine)

# create all tables if you wish...
Base.metadata.create_all(engine)

app = flask.Flask(__name__)

@app.before_request
def create_session():
    flask.g.session = Session()

@app.teardown_appcontext
def shutdown_session(response_or_exc):
    flask.g.session.commit()
    flask.g.session.remove()

@app.route('/')
    # just use the SQLAlchemy session :)
    items = flask.g.session.query(Item).all()
    return flask.render_template('index.html', items=items)
Run Code Online (Sandbox Code Playgroud)

参见我的示例Flask + SQLAlchemy应用程序:https : //github.com/messa/db-workshop-web-app/blob/sqlalchemy/anketa.py

如您所见,您甚至可以将所有内容放在一个大文件上,但将其拆分为多个文件(其中一个通常命名为model.py)是最佳实践。

最重要的是在各个请求之间建立隔离的会话 -在我的解决方案中,为before_request挂接中的每个请求创建会话。Flask docs“ Flask中的SQLAlchemy”中的解决方案使用scoped_session的效果基本相同(使用线程局部变量,每个线程使用一个单独的会话来实现)。

广告应用程序架构:对于大型应用程序,最好使用大型应用程序模式蓝图。因此,我所有的get_app()Flask 路由处理程序都将包含在蓝图中,然后我将拥有一个“主要”功能,即1)创建Flask对象2)向其注册蓝图3)创建SQLAlchemy引擎并Session()与Flask 挂钩app.before_request。大致相似,还是这个


你应该只有一个引擎

为什么?从技术上讲,引擎只是数据库的连接(池)。如果您的应用程序使用三个独立的数据库怎么办?然后,您当然需要三个引擎。

但是,当然,一个会话仅连接到一个引擎。因此,您将需要多个会话。以及模型类的多个声明式基础,并且-最重要的是-不要将其偶然混合在一起。因此,建议尽可能只使用一个引擎。

您可以根据请求创建引擎-从技术上讲这是正确的,但是效率很低。为整个应用程序保留一个引擎,仅根据每个请求创建会话。