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

问题描述 投票:12回答:3

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

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

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

我的问题是这些:

  1. 您是否可以在上面的示例中提供实际用例,或者您自己的数据映射器模式有用的示例?我读到的每个地方都是数据映射器模式在复杂情况下很有用,但没有看到示例。
  2. 在上述情况下使用存储库模式与使用数据映射器模式相同吗?
  3. 数据映射器拥护者是否在与示例中所做的模型不同的类中编写选择查询?
  4. 为什么Question.query.filter_by(text = text).all()不比db.session.query(Question).filter(Question.text == text).all()更好用?

这不是DataMapper vs ActiveRecord pattern的重复,因为这只是告诉定义,我对实际例子更感兴趣。

python design-patterns activerecord flask-sqlalchemy datamapper
3个回答
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()使用显式交易。

明确的交易让您高枕无忧。当您查询快速变化的数据库并希望您的几个相关selects看到相同的一致状态时,它们对于selects也很重要。

我经常在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%的情况下足够。但有时你需要更精细的粒度。


3
投票

完全同意上面的答案:是的,SQLAlchemy的Data Mapper模式真的更灵活,对于复杂的查询,它真的更强大,更不神奇,更有控制。

但是,在CRUD这样的简单任务中,SQLAlchemy的代码变得过于过重/过度/冗余。

例如,要在最简单的“创建”控制器中创建一些对象,您需要这样的东西:

user = User(name='Nick', surname='Nickson')
session.add(user)
session.flush()

在Active Record ORM中,您只需要单个字符串。

好吧,对于简单的任务,我们中的一些人可能想要更简单的东西。我的意思是拥有SQLAlchemy的Active Record会很酷。

好消息:我最近为此创建了包(它还包含其他有用的东西)。

看看:https://github.com/absent1706/sqlalchemy-mixins


0
投票
  1. 我将使用Data Mapper而不是Active Record的唯一原因是你有严重的可扩展性问题。 Data Mapper鼓励分离域对象和数据库访问逻辑,而Active Records将数据库访问逻辑放在域对象中。例如,当您解除Flask实例时,它将仅按需连接到数据库,而在Django中,它将始终连接到数据库。
  2. Data Mapper将域对象与数据库访问逻辑隔离,而Repository模式是域对象和Data Mapper之间的层。它比Data Mapper高一级。例如,在Data Mapper模式中,您将拥有简单的getter和setter,在存储库模式中,您将拥有可能还包含一些复杂业务逻辑的getter和setter。
  3. Data Mapper与模型类分开。只有Active Record模式连接同一类中的getter和setter。
  4. 我已经和SQLAlchemy和Django一起工作了一段时间,我绝对喜欢Django之类的查询。对于我自己的项目,我使用Flask + SQLAlchemy而不是Django的可能性几乎为零。在考虑这两个框架时,生产力和社区是决定性的两个因素。
© www.soinside.com 2019 - 2024. All rights reserved.