简介
对象关系映射器(Object Relational Mappers,ORM)在过去数年吸引了不少人的目光。主要原因是 ORM 经常会在 Web 应用程序框架中被提起,因为它是快速开发(Rapid Development)栈中的关键组件。Django 和 Ruby on Rails 等 Web 框架采用了设计一个独立栈的方法,将自主开发的 ORM 紧密集成到该框架中。而其他框架,如 Pylons、Turbogears 和 Grok,则采用更加基于组件的架构结合可交换的第三方组件。两种方法都有各自的优势:紧密集成允许非常连贯的体验(如果问题映射到框架),而基于组件的架构则允许最大的设计灵活性。但是,本文的主题并不是 Web 框架;而是 SQLAlchemy。
SQLAlchemy 在构建在 WSGI 规范上的下一代 Python Web 框架中得到了广泛应用,它是由 Mike Bayer 和他的核心开发人员团队开发的一个单独的项目。使用 ORM 等独立 SQLAlchemy 的一个优势就是它允许开发人员首先考虑数据模型,并能决定稍后可视化数据的方式(采用命令行工具、Web 框架还是 GUI 框架)。这与先决定使用 Web 框架或 GUI 框架,然后再决定如何在框架允许的范围内使用数据模型的开发方法极为不同。
SQLAlchemy 的一个目标是提供能兼容众多数据库(如 SQLite、MySQL、Postgres、Oracle、MS-SQL、SQLServer 和 Firebird)的企业级持久性模型。SQLAlchemy 正处于积极开发阶段,当前最新的 API 将围绕版本 0.5 设计。请参阅参考资料部分,获取官方 API 文档、教程和 SQLAlchemy 书籍的链接。
SQLAlchemy 取得成功的一个证明就是围绕它已建立了丰富的社区。针对 SQLAlchemy 的扩展和插件包括:declarative、Migrate、Elixir、SQLSoup、django-sqlalchemy、DBSprockets、FormAlchemy 和 z3c.sqlalchemy。在本文中,我们将学习一篇关于新 0.5 API 的教程,探究一些第三方库,以及如何在 Pylons 中使用它们。
安装
本文假定您使用 Python 2.5 或更高版本,并且安装了子版本。Python 2.5 包括 SQLite 数据库,因此也是测试 SQLALchemy 内存的好工具。如果您已经安装了 Python 2.5,则只需通过设置工具安装 sqlalchemy 0.5 beta 。要获取设置工具脚本,请在您的终端中下载并运行以下 4 条命令:
wget http://peak.telecommunity.com/dist/ez_setup.py python ez_setup.py sudo easy_install http://svn.sqlalchemy.org/sqlalchemy/trunk sudo easy_install ipython
前三行代码检查最新版本的 sqlalchemy,并将它作为包添加到您本地系统的 Python 安装中。最后一个代码片段将安装 IPython,它是一个实用的声明式 Python 解释器,我将在本文中使用它。首先,我需要测试已安装的 SQLAlchemy 版本。您可以测试自己的版本是否为 0.5.x,方法是在 IPython 或普通 Python 解释器中发起以下命令。
In [1]: import sqlalchemy In [2]: sqlalchemy.__version__ Out[2]: '0.5.0beta1'
SQLAlchemy 0.5 快速入门指南
新的 0.5 发行版在 SQLAlchemy 中引入了一些显著的变更。此外列出了这些变更的概要信息:
- 声明式扩展是多数情况下建议的开始方式。
- session.query() 可以接受任意组合的 class/column 表达式。
- session.query() 或多或少也是 select() 的支持 ORM 的替代方法。
- 查询提供了一些试验性的 update()/delete() 方法,用于实现基于标准的更新/删除。
- 会话将在 rollback() 和 commit() 方法后自动过期;因此使用默认的 sessionmaker() 意味着您通常不必调用 clear() 或 close();对象将自动与当前的事务同步。
- 使用 session.add()、session.add_all()(save/update/save_or_update 已删除)在会话中添加内容。
虽然 declarative 扩展从 0.4 开始便一直出现在 SQLAlchemy 中,但它也经过了一些小修改,这使它在大多数 SQLAlchemy 项目中都成为了一种强有力的便捷方式。新的 declarative 语法允许在一步中创建表、类和数据库映射。下面我们来看看这种新语法的工作原理,以我编写的一个用于跟踪文件系统变化的工具为例。
清单 1. 新 SQLAlchemy 声明样式
#/usr/bin/env python2.5 #Noah Gift from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey Base = declarative_base() class Filesystem(Base): __tablename__ = 'filesystem' path = Column(String, primary_key=True) name = Column(String) def __init__(self, path,name): self.path = path self.name = name def __repr__(self): return "<Metadata('%s','%s')>" % (self.path,self.name)
通过这种新的声明样式,SQLAlchemy 能够在一步中创建一个数据库表、创建一个类以及类与表之间的映射。如果您刚开始接触 SQLAlchemy,或许应该学习这种建立 ORM 的方法。此外,了解另一种更加显式地控制各步骤的方式也是有益的(如果您的项目要求这种级别的详细程度)。
在阅读这段代码时,需要指出一些可能会让初次接触 SQLAlchemy 或声明性扩展的用户犯难的地方。首先,
Base = declarative_base()
行创建了一个类,稍后的 Filesystem 类便继承自该类。如果您保存并在 declarative_style 中运行该代码,然后将它导入到 IPython 中,则会看到以下输出:
In [2]: declarative_style.Filesystem? Type: DeclarativeMeta Base Class: <class 'sqlalchemy.ext.declarative.DeclarativeMeta'> String Form: <class 'declarative_style.Filesystem'>
这个 DeclarativeMeta 类型的魔力就是允许所有操作发生在一个简单的类定义中。
另一个需要指出的地方是本示例并未实际执行任何操作。在运行创建表的代码之前,将不会创建实际的表,并且,您还需要定义 SQLAlchemy 将使用的数据库引擎。这两行代码如下所示:
engine = create_engine('sqlite:///meta.db', echo=True) Base.metadata.create_all(engine)
SQlite 是试验 SQLAlchemy 的理想选择,并且您还可以选择使用内存数据库,在这种情况下,您的代码行应如下所示:
engine = create_engine('sqlite:///:memory:', echo=True)
或者,只创建一个简单的文件,如第一个例子所示。如果您选择创建一个基于 SQLite 文件的数据库,则可以通过抛弃数据库中的所有表从零开始,而不需要删除文件。为此,您可以发起以下代码行:
Base.metadata.drop_all(engine)
此时,我们已经了解了创建 SQLAlchemy 项目和通过 SQLAlchemy API 控制数据库所需的知识。