在Flask中正确使用SQLAlchemy

6
我正在使用flask和sqlalchemy制作一个基本的API,只是为了好玩。我在sqlalchemy文档中读到,你应该只有一个带有连接字符串的引擎。这个引擎应该如何在应用程序中构建?在__init__.py文件中吗?还是在运行flask服务器的flask文件中?在这里是我的github存储库,因为我认为这样更容易看到当前应用程序结构和任何缺陷。https://github.com/JayHelton/Geekdom_Web_App 在我的查询方法中,我每次都会创建一个新的DB引擎,似乎它正在工作,但我不想遇到如果多个人尝试调用这些方法的问题。谢谢!
2个回答

17

当然,已经有一个Flask扩展 Flask-SQLAlchemy - 也在Flask文档 SQLAlchemy in Flask中提到。但像大多数Flask扩展一样,它所做的只是将Flask和SQLAlchemy(或任何其他库)“连接”起来。最好的文档通常是源代码 :)

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

然而,对于Flask-SQLAlchemy来说,它包含了大量的代码和一些关于作用域会话、Flask上下文、修改跟踪和持续调试以及在Web应用程序中非常有用的内容以及所有可能的角落和边角情况和其他一些东西的黑魔法。我认为这有点过度设计。我并不是说你不应该使用它 - 只是SQLAlchemy和Flask之间的连接在扩展代码中并不明显,因此可能需要更多的阅读时间。
但是,如果您希望自己完成,那么非常容易(就像SQLAlchemy可以做到的那样)-只需初始化SQLAlchemy,以便您获得一个“sessionmaker”,然后在每个请求之前创建一个会话,然后不要忘记在请求后关闭它 :) ,并且在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)

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

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

最重要的是在各个请求之间具有隔离的会话 - 在我的解决方案中,会话是在before_request钩子中为每个请求创建的。Flask文档中"SQLAlchemy in Flask"的解决方案使用scoped_session,它基本上具有相同的效果(使用线程本地变量实现每个线程的单独会话)。

广告应用程序架构:对于更大的应用程序,最好使用更大的应用程序模式蓝图。所以我的所有flask路由处理程序都将在蓝图中,然后我会有一个"main"函数get_app(),它会 1)创建Flask对象 2)向其注册蓝图 3)创建SQLAlchemy引擎并将Session()钩子与Flask app.before_request连接起来。大致类似于这个这个


你应该只有一个引擎

为什么?从技术上讲,引擎只是连接到数据库的连接池。如果您的应用程序使用三个单独的数据库呢?那么您当然需要三个引擎。

但是,会话当然连接到恰好一个引擎。因此,您需要多个会话。以及多个声明性基础模型类,并且最重要的是不要意外混淆它们。这就是为什么建议只有一个引擎 - 如果可能的话。

您可以根据请求创建引擎 - 这在技术上是正确的,但效率低下。保持整个应用程序的一个引擎,只需每个请求创建一个会话。


非常感谢您的回答,我是 Flask 的新手,并且一直在使用带有 SQLALCHEMY 实例的 sqlite 数据库来运行整个应用程序,我从未使用过那个 engine 变量,所以它是否与 sqlite 兼容,或者我应该切换到 postgres?此外,为什么要使用引擎而不仅仅依赖于数据库会话?非常感谢您的帮助。 - BHA Bilel
1
引擎是连接池,会话则是ORM对象,同时也使用了来自连接池(引擎)的连接。请注意,在我的例子中,我基本上只在设置中使用引擎,在应用程序代码(flask处理器)中则使用会话。在这一点上,SQLite和PostgreSQL之间没有区别(如果我们排除仅为内存的SQLite)。 - Messa

0
一旦您在Flask应用程序上安装了SQLAlchemy,您将需要创建一个单独的*.py文件来存储数据库配置,并使用导入语句将其并入其他.py文件以供使用。
如果您想在应用程序本身中查看/创建API数据的表,则它们将驻留在类似“models.py”的文件中,该文件还会导入db连接字符串。
这是一个相当不错的Flask + SQLAlchemy todo应用程序教程,链接指向她详细描述文件结构和数据库实现的部分。

http://www.vertabelo.com/blog/technical-articles/web-app-development-with-flask-sqlalchemy-bootstrap-part-2

以下是一个链接,其中包含更通用但也详细的步骤,介绍如何在Flask中设置SQLAlchemy数据库,并且还涵盖了一些使用ORM查询而不是原始SQL查询的示例(尽管我通常使用原始SQL查询 - 因为我通常也安装MySQL并在MySQL Workbench中创建表,但这可能对于仅使用API数据的应用程序来说有点过度)。

http://flask.pocoo.org/docs/0.12/patterns/sqlalchemy/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接