Flask SQLAlchemy数据映射器与活动记录模式

时间:2017-02-24 19:57:39

标签: python design-patterns activerecord flask-sqlalchemy datamapper

我最近开始研究Flask和Flask-SQLAlchemy。来自Django背景我发现Flask-SQLAlchmey非常复杂。我已经读过SQLAlchemy实现了Data Mapper模式,而Django ORM则基于Active Record Pattern。

Here是一个编写的示例代码,用于实现存储库模式以访问数据库。

Here是S.Lott(271k声誉)评论的另一个链接,他说ORM是数据访问层,它与模型分开。

我的问题是这些:

  1. 您是否可以在上面的示例中提供实际用例,或者您自己的数据映射器模式有用的示例?我读到的每个地方都是数据映射器模式在复杂情况下很有用,但没有看到示例。
  2. 使用与上述情况相同的存储库模式与使用数据映射器模式相同吗?
  3. 数据映射器的拥护者是否在模型中创建了与模型不同的类中的选择查询?
  4. 为什么db.session.query(Question).filter(Question.text == text).all()不能比使用更好 {{1}}?
  5. 这不是DataMapper vs ActiveRecord pattern的重复,因为这只是告诉定义,我对实际例子更感兴趣。

3 个答案:

答案 0 :(得分:3)

逐点。

1。

我有一个遗留数据库,我必须编写一些数据处理实用程序。使用Mapper模式,没有ORM / ActiveRecord样式,在编写像ActiveRecord那样的查询时,对我来说简单易行。它运行在类似于SQL子句的良好可组合对象上,不受SQL注入的影响。

“被动”对象允许更多的灵活性/一致性:复杂连接的结果是命名元组,这是简单选择的结果。没有可关心的身份,没有具有相同身份的缓存对象。

所有更新都是明确的;不是某个州在其他地方改变的“保存”,没有在.save()上运行的挂钩等。这使得有效的批量更新变得微不足道,如果将正确的数据发送到数据库,则不会有麻烦。两者都是我的好处。一般情况下,“这取决于”。例如,我必须在插入后手动获取数据库生成的ID。显式运行此查询是一项额外的工作。能够在一个查询中执行此操作而不是每个记录一个,这对我来说是一个巨大的好处。

SQLAlchemy具有分层设计,允许您访问较低的“映射器”级别,即使您在较高的ORM级别上声明事物并且通常对其进行操作也是如此。例如,在Django中,如果/仍然可能的话,它并不那么简单。

2

在示例中,“存储库”看起来像是在上面构建的级别。存储库可以构建在纯DBAPI之上,但映射器使一些事情更简单,例如更好的参数绑定,结果集的命名元组,以及带有可组合,可重用部分的纯SQL之上的包装器。

映射器还提供一定程度的数据库独立性。例如。 SQL Server和Postgres有不同的方法来连接字符串;映射器提供统一的接口。

3

您在select处写下您使用它的地方。如果您有一个在不同上下文中不断重用的选择,则可以将其放入方法或函数中。大多数选择都有一个用途,并在现场制作。

SQLAlchemy设计的一个很好的特性是,您可以轻松地存储条件和整个where子句,并在select / update / delete语句中重用它们。

4

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)

  1. 之所以要在Active Record上使用Data Mapper,是因为您遇到了严重的可伸缩性问题。 Data Mapper鼓励将域对象和数据库访问逻辑分开,而Active Records将数据库访问逻辑放在域对象中。例如,当您举起Flask实例时,它将仅根据需要连接到数据库,而在Django中,它将始终连接到数据库。

  2. 数据映射器将域对象与数据库访问逻辑隔离开来,而存储库模式是域对象和数据映射器之间的一层。它比Data Mapper高。例如,在Data Mapper模式中,您将具有直接的getter和setter,在存储库模式中,将具有可能还包含一些复杂业务逻辑的getter和setter。

  3. 数据映射器与模型类分开。只有Active Record模式才能将同一类中的getter和setter联接起来。

  4. 我已经使用SQLAlchemy和Django一段时间了,我当然更喜欢Django之类的查询。对于我自己的项目,我对Django使用Flask + SQLAlchemy的可能性几乎为零。在考虑这两个框架时,生产力和社区是两个最主要的决定因素。