我最近开始研究Flask和Flask-SQLAlchemy。来自Django背景我发现Flask-SQLAlchmey非常复杂。我已经读过SQLAlchemy实现了Data Mapper模式,而Django ORM则基于Active Record Pattern。
Here是一个编写的示例代码,用于实现存储库模式以访问数据库。
Here是S.Lott(271k声誉)评论的另一个链接,他说ORM是数据访问层,它与模型分开。
我的问题是这些:
db.session.query(Question).filter(Question.text == text).all()
不能比使用更好
{{1}}?这不是DataMapper vs ActiveRecord pattern的重复,因为这只是告诉定义,我对实际例子更感兴趣。
答案 0 :(得分:3)
逐点。
我有一个遗留数据库,我必须编写一些数据处理实用程序。使用Mapper模式,没有ORM / ActiveRecord样式,在编写像ActiveRecord那样的查询时,对我来说简单易行。它运行在类似于SQL子句的良好可组合对象上,不受SQL注入的影响。
“被动”对象允许更多的灵活性/一致性:复杂连接的结果是命名元组,这是简单选择的结果。没有可关心的身份,没有具有相同身份的缓存对象。
所有更新都是明确的;不是某个州在其他地方改变的“保存”,没有在.save()
上运行的挂钩等。这使得有效的批量更新变得微不足道,如果将正确的数据发送到数据库,则不会有麻烦。两者都是我的好处。一般情况下,“这取决于”。例如,我必须在插入后手动获取数据库生成的ID。显式运行此查询是一项额外的工作。能够在一个查询中执行此操作而不是每个记录一个,这对我来说是一个巨大的好处。
SQLAlchemy具有分层设计,允许您访问较低的“映射器”级别,即使您在较高的ORM级别上声明事物并且通常对其进行操作也是如此。例如,在Django中,如果/仍然可能的话,它并不那么简单。
在示例中,“存储库”看起来像是在
映射器还提供一定程度的数据库独立性。例如。 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()
使用显式交易。
显式交易让您可以放心使用DML。当您查询快速更改的数据库并希望您的多个相关select
看到相同的一致状态时,它们对select
也很重要。
我通常在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%的情况下足够。但有时你需要更精细的粒度。
答案 1 :(得分:3)
完全同意上述答案:是的,SQLAlchemy的Data Mapper模式实际上更灵活,对于复杂的查询,它实际上更强大,更不神奇,更有控制。
但是,在诸如docs之类的简单任务中,SQLAlchemy的代码变得过于过重/过度/冗余。
例如,要在最简单的“创建”控制器中创建一些对象,您需要这样的东西:
(4118181 {'last_name': 'Belousov', 'first_name': 'Mikhail'})
在Active Record ORM中,您只需要单个字符串。
嗯,对于简单的任务,我们中的一些人可能想要更简单的东西。 我的意思是为SQLAlchemy创建Active Record会很酷。
好消息:我最近为此创建了包(它还包含其他有用的东西)。
检查出来:https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html
答案 2 :(得分:0)
之所以要在Active Record上使用Data Mapper,是因为您遇到了严重的可伸缩性问题。 Data Mapper鼓励将域对象和数据库访问逻辑分开,而Active Records将数据库访问逻辑放在域对象中。例如,当您举起Flask实例时,它将仅根据需要连接到数据库,而在Django中,它将始终连接到数据库。
数据映射器将域对象与数据库访问逻辑隔离开来,而存储库模式是域对象和数据映射器之间的一层。它比Data Mapper高。例如,在Data Mapper模式中,您将具有直接的getter和setter,在存储库模式中,将具有可能还包含一些复杂业务逻辑的getter和setter。
数据映射器与模型类分开。只有Active Record模式才能将同一类中的getter和setter联接起来。
我已经使用SQLAlchemy和Django一段时间了,我当然更喜欢Django之类的查询。对于我自己的项目,我对Django使用Flask + SQLAlchemy的可能性几乎为零。在考虑这两个框架时,生产力和社区是两个最主要的决定因素。