爱上 SQLAlchemy 的 10 个理由(转)

2023-07-08 10:00 11次浏览 经验

12345class OrderItem(Base):id = Column(Integer, primary_key=True)order = many_to_one(‘Order‘)product = many_to_one(‘Product‘)quantity = Column(Integer)定义数据库模式的 Python 代码在 SQLAlchemy 中叫做模型(model)。
因为这些模型都是用 Python 的类实现的,所以你可以添加自己的类方法。这样可以把相关功能放在一起方便维护。Python12345class Order(Base):def update_stock(self):for item in self。
items:item。product。stock -= item。quantity上面这个例子说明了,在 SQLAlchemy 中数据库的模式也可以通过版本控制来维护。所以使用SQLAlchemy 的同时,你也可以享受到版本控制的诸多便利:比如版本追踪、标签、追溯(blame)等等。
2、自动同步模型到数据库模式Alembic 是 SQLAlchemy 的一个数据库管理插件。当你修改模型的时候,Alembic 可以自动更新数据库模式。使用 Alembic 来做一些添加表或者列的小改动是非常便捷快速的。Python1234$ alembic upgrade headINFO[alembic。
context] Context class PostgresqlContext。INFO[alembic。context] Will assume transactional DDL。INFO[alembic。context] Running upgrade None -> 1975ea83b712尽管在开发环境中自动同步非常方便,但是大多数人还是想在生产环境中采用更稳妥一些的方式。
这一点 Alembic 也想到了,它可以自动生成修改的脚本,数据库管理员可以在检视脚本之后再应用到生产环境的数据库上。3、Pythonic 的代码风格让你的代码更易读SQLAlchemy 使用更 Pythonic 的方式表示数据库关系,这对于阅读和编写代码来说是非常方便的。
我们来看下面这个例子,这个例子可以打印出在一个订单中的所有产品。Python12for item in order。items:print(item。product。name, item。quantity)代码非常的简单易读,但是打通了两个数据库,执行了 JOIN 连接查询。
order。items是一对多的关系,SQLAlchemy 会自动加载 OrderItem 中和这个订单相关的对象。item。product则储存的是多对一的关系,SQLAlchemy 会自动加载对应的产品。SQLAlchemy 也可以运用类。
如果应用修改了一个有映射的字段,对象会自动请求写入数据库。这个功能使编写应用逻辑的时候没有了后顾之忧。4、用 Python 构建查询语句类似用主键获取对象这种简单查询只需要很少的代码:Python1order = session。query(Order)。
get(order_id)使用 Python 的查询语法,我们可以实现更复杂的查询。比如下面的例子,我要查找两天以前的有效订单:Python12overdue_orders = session。query(Order)。filter(Order。
status == ‘active‘&& Order。time < datetime。now() – timedelta(days=2))SQLAlchemy 的语法可以让你把 SQL 语句和 Python 的变量结合起来,并且可以杜绝 SQL 注入攻击。
SQLAlchemy 会在内部重载各种比较运算符,然后将它们转换成 SQL 语句。当你执行一条非常复杂的查询时,使用 SQLAlchemy 语法来定义查询也是可以的。但是我认为 SQLAlchemy 可以胜任的查询复杂程度是有限的,某些时候直接写 SQL 语句可能更容易些。
在这种情况下,你可以定义数据库视图来完成复杂查询,SQLAlchemy 可以把视图映射到 Python 对象。5、与 Web 框架的无缝集成有些框架默认支持SQLALchemy,比如说 Pyramid。对于其他 web 框架,你需要安装一个集成库来支持 SQLAlchemy,比如说用于 Flask 的 Flask-SQLAlchemy 或者用于 Django 的 aldjemy。
SQLAlchemy 会维持一个连接池,为每一个 web 请求提供一个可用的数据库连接。那些支持库可以处理常见异常,提高应用的健壮性,让应用在某些异常情况下不至于崩溃,比如运行时重启数据库这样的操作。每一个请求都会用事务包裹起来,如果请求成功就提交事务,否则就回滚。
这种设计使得外部方法能够正确地与数据库交互,而不需要关心具体的数据库处理代码。6、预先加载提高性能大部分 ORM 都使用的是延迟加载策略。在第一次调用关系时,一次 SQL 查询会执行,加载数据。像上面的例子,order。items的调用实际上执行了一次 SQL 查询,之后的每次使用item。
product都会发起另外的查询。因为item。product是在一个循环中调用的,所以会生成大量的 SQL 查询,导致性能降低。这种情况叫做“n+1 选择问题”SQLAlchemy 针对上述问题有一个解决方案:预先加载(eager loading)。
当我们第一次加载Order这个对象时,我们可以通知 SQLAlchemy 我们会使用那些关系,然后 SQLAlchemy 就能在一次查询中加载所有数据,语法如下所示:Python1session。query(Order)。options(joinedload_all(‘items。
product‘))。get(order_id)7、透明的多态支持像 Python 这样的面向对象语言是鼓励使用多态的。如果有一个Person的基类,我们就可以基于Person来创建子类,比如 增加了新字段的Employee或者Customer类。
但是传统的 SQL 数据库不支持多态,所以 ORM 想要支持多态也是有心无力。但是 SQLAlchemy 在 SQL 中完美地模拟了多态。我们在 Python 代码中可以非常自然地使用多态,数据库中的数据也可以通过 SQL 便捷地获取。在应用代码中我们可以轻松地使用多态类,而不需要关心它们究竟是怎么存储的。
8、兼容已有数据库一些 ORM 要求你的数据库结构满足既定条件,强制每张表都有单一主键列,甚至主键名称必须是 “id”如果你从头建立一个数据库,这些限制并不是问题。但是如果你想用以前的数据库,这些限制条件会阻止你访问那些不满足条件的表。
SQLAlchemy 不会假定你的数据库结构,所以可以完美支持以前的数据库。还有一个叫做 sqlacodegen 的工具可以根据已有的数据库生成 SQLAlchemy 模型。SQLAlchemy 使得你可以通过简单的 Python 脚本和以前的数据库进行交互。
9、提供许多钩子函数让你自定义库SQLAlchemy 拥有清晰的分层架构。几乎任何 SQLAlchemy 库都可以被重写以满足特定需求。当在有多个使用者的云应用上工作的时候,我发现了一个非常有用的功能。比如说应用中大多数查询都包含了过滤条件,只返回当前使用者的结果。
就像下面这个例子:Python1products = session。query(Product)。filter(Product。merchant == current_user。merchant)。all()但是我发现,如果一不小心忘记加过滤条件的话,可能让某个用户可以看到其他经销商的信息,而这是不允许的。
谨慎起见,我们可以创建一个自定义的 SQLAlchemy 的session工厂函数,可以在会话中自动给所有查询应用过滤条件。虽然只是这么一点小小的控制代码,却可以让你的应用安全系数更高。10、完善的文档有些开源项目的文档的确是漏洞百出,但是 SQLAlchemy 不是这样。
SQLAlchemy 的文档非常详尽,并且还有从简单例子到高级特性的学习指南,以及全面的 API 参考文档。这对于开发人员学习和使用 SQLAlchemy 是非常有帮助的。爱上 SQLAlchemy 的 10 个理由(转)。