我最近开始研究Flask和Flask-SQLAlchemy。来自Django背景我发现Flask-SQLAlchmey非常复杂。我已经读过,SQLAlchemy实现了Data Mapper模式,而Django ORM则基于Active Record Pattern。
Here是一个编写的示例代码,它实现了访问数据库的存储库模式。
Here是S.Lott(271k声誉)评论的另一个链接,他说ORM是数据访问层,它与模型分开。
我的问题是这些:
Question.query.filter_by(text = text).all()
不比db.session.query(Question).filter(Question.text == text).all()
更好用?这不是DataMapper vs ActiveRecord pattern的重复,因为这只是告诉定义,我对实际例子更感兴趣。
一点一点地说。
我有一个遗留数据库,我必须编写一些数据处理实用程序。使用Mapper模式,没有ORM / ActiveRecord样式,在编写像ActiveRecord那样的查询时,对我来说简单易行。它运行在类似于SQL子句的良好可组合对象上,不受SQL注入的影响。
被动对象允许更多的灵活性/统一性:复杂连接的结果是一个命名元组,这是简单选择的结果。没有任何标识可以关注,没有具有相同标识的缓存对象。
所有更新都是明确的;不是某个状态在其他地方改变的“保存”,没有在.save()
上运行的挂钩等。这使得有效的批量更新变得微不足道,如果将正确的数据发送到数据库则不会有麻烦。两者都是我的好处。一般情况下,“这取决于”。例如,我必须在插入后手动获取数据库生成的ID。显式运行此查询是一项额外的工作。能够在一个查询中执行此操作而不是每个记录一个,这对我来说是一个巨大的好处。
SQLAlchemy具有分层设计,允许您访问较低的“映射器”级别,即使您在较高的ORM级别上声明事物并且通常对其进行操作也是如此。例如,在Django中,如果/仍然可能的话,它并不那么简单。
在示例中,“存储库”看起来像是在“映射器”之上构建的级别。存储库可以构建在纯DBAPI之上,但映射器使一些事情更简单,例如更好的参数绑定,结果集的命名元组,以及带有可组合,可重用部分的纯SQL之上的包装器。
映射器还提供一定程度的数据库独立性。例如。 SQL Server和Postgres有不同的方法来连接字符串;映射器提供统一的接口。
你在用它的地方写下你的select
。如果您有一个在不同上下文中不断重用的选择,则可以将其放入方法或函数中。大多数选择都有一个用途,并在现场建立。
SQLAlchemy设计的一个很好的特性是,您可以轻松地存储条件和整个where
子句,并在select / update / delete语句中重用它们。
Question.query.filter_by(text = text).all()
使用隐式交易。 db.session.query(Question).filter(Question.text == text).all()
使用显式交易。
明确的交易让您高枕无忧。当您查询快速变化的数据库并希望您的几个相关select
s看到相同的一致状态时,它们对于select
s也很重要。
我经常在sessionmaker
周围写一个简单的包装器并写下这样的东西:
with my_database.transaction() as trans:
records = trans.query(...)
...
updated = trans.execute(...).rowcount
# Here the transaction commits if all went well.
当我确定不知道DML应该在这个块中运行时,我使用总是回滚的.readonly_transaction()
。
在许多情况下,隐式交易很好。 Django允许您使用@transaction.atomic
修饰方法并具有半显式事务控制,在99%的情况下足够。但有时你需要更精细的粒度。
完全同意上面的答案:是的,SQLAlchemy的Data Mapper模式真的更灵活,对于复杂的查询,它真的更强大,更不神奇,更有控制。
但是,在CRUD这样的简单任务中,SQLAlchemy的代码变得过于过重/过度/冗余。
例如,要在最简单的“创建”控制器中创建一些对象,您需要这样的东西:
user = User(name='Nick', surname='Nickson')
session.add(user)
session.flush()
在Active Record ORM中,您只需要单个字符串。
好吧,对于简单的任务,我们中的一些人可能想要更简单的东西。我的意思是拥有SQLAlchemy的Active Record会很酷。
好消息:我最近为此创建了包(它还包含其他有用的东西)。