连接到数据库¶
在开始使用实体之前,您需要创建 Database
对象。您在 Python 代码中声明的实体将通过此对象映射到数据库。
将实体映射到数据库可以分为四个步骤
现在我们将描述使用 Database
对象及其方法的主要工作流程。如果您需要更多详细信息,可以在 API 参考 中找到。
创建数据库对象¶
在此步骤中,我们只需创建一个 Database
类的实例
db = Database()
将数据库对象绑定到特定数据库¶
在将实体映射到数据库之前,我们需要连接到它以建立连接。可以使用 bind()
方法完成此操作
db.bind(provider='postgres', user='', password='', host='', database='')
此方法的第一个参数是数据库提供程序的名称。数据库提供程序是一个位于 pony.orm.dbproviders
包中的模块,它知道如何与特定数据库进行交互。在数据库提供程序名称之后,您应该指定将传递给相应 DBAPI 驱动程序的 connect()
方法的参数。
目前,Pony 可以与以下数据库系统一起使用:SQLite、PostgreSQL、MySQL、Oracle、CockroachDB,相应的 Pony 提供程序名称为:'sqlite'
、'postgres'
、'mysql'
、'oracle'
和 'cockroach'
。Pony 可以轻松扩展以合并其他数据库提供程序。
当您刚开始使用 Pony 时,可以使用 SQLite 数据库。此数据库包含在 Python 发行版中,您无需单独安装任何内容。使用 SQLite,您可以在文件或内存中创建数据库。要创建文件中的数据库,请使用以下命令
db.bind(provider='sqlite', filename='database.sqlite', create_db=True)
当 create_db=True
时,如果数据库文件不存在,Pony 将创建它。如果它已经存在,Pony 将使用它。
对于内存数据库,如果您从单个线程工作,请使用此方法
db.bind(provider='sqlite', filename=':memory:')
…以及此方法,如果您需要从多个线程访问同一个内存数据库
db.bind(provider='sqlite', filename=':sharedmemory:')
创建内存数据库时,无需使用参数 create_db
。这是一种在交互式 shell 中使用 Pony 时创建 SQLite 数据库的便捷方法,但您应该记住,整个内存数据库将在程序退出时丢失。
以下是绑定到其他数据库的示例
db.bind(provider='sqlite', filename=':sharedmemory:')
db.bind(provider='sqlite', filename='filename', create_db=True)
db.bind(provider='mysql', host='', user='', passwd='', db='')
db.bind(provider='oracle', user='', password='', dsn='')
db.bind(provider='cockroach', user='', password='', host='',
database='', sslmode='disable')
您可以在 API 参考中找到有关使用每个数据库的更多详细信息
将实体映射到数据库表¶
创建 Database
对象、定义实体并绑定数据库后,下一步是使用 generate_mapping()
方法将实体映射到数据库表
db.generate_mapping(create_tables=True)
此方法创建表、外键引用和索引(如果它们不存在)。映射实体后,您可以在 Python 代码中开始使用它们 - 选择、创建、修改对象并将它们保存到数据库中。
数据库对象的方法和属性¶
使用数据库对象进行原始 SQL 查询¶
通常,您将使用实体并让 Pony 与数据库进行交互,但 Pony 还允许您使用 SQL 与数据库进行交互,甚至将这两种方式结合起来。当然,您可以使用 DBAPI 接口直接与数据库进行交互,但使用 Database
对象可以为您提供以下优势
使用
db_session()
装饰器或上下文管理器进行自动事务管理。在事务完成后,所有数据将存储到数据库中,或者如果发生异常,则回滚。连接池。无需跟踪数据库连接。您在需要时拥有连接,并在完成事务后,连接将返回到池中。
统一的数据库异常。每个 DBAPI 模块都定义了自己的异常。Pony 允许您在使用任何数据库时使用相同的异常集。这有助于您创建可以从一个数据库移植到另一个数据库的应用程序。
将参数传递给 SQL 查询的统一方式,并防止注入攻击。不同的数据库驱动程序使用不同的参数样式 - DBAPI 规范提供了 5 种不同的将参数传递给 SQL 查询的方式。使用
Database
对象,您可以对所有数据库使用一种传递参数的方式,并消除 SQL 注入的风险。使用
get()
或select()
方法时,自动解包单列结果。如果select()
方法只返回一列,Pony 返回一个值列表,而不是一个元组列表,每个元组只有一个项目,就像 DBAPI 一样。如果get()
方法返回一列,它只返回一个值,而不是一个包含一个项目的元组。这很方便。当方法
select()
或get()
返回多列时,Pony 使用智能元组,允许使用列名而不是元组索引来访问项目作为元组属性。
换句话说,Database
对象可以帮助您节省完成例行任务的时间,并提供便利性和统一性。
在原始 SQL 查询中使用参数¶
使用 Pony,您可以轻松地将参数传递到 SQL 查询中。要指定参数,您需要在变量名前面加上 $ 符号
x = "John"
data = db.select("select * from Person where name = $x")
当 Pony 在 SQL 查询中遇到这样的参数时,它会从当前帧(从全局变量和局部变量)或从作为第二个参数传递的字典中获取变量值。在上面的示例中,Pony 将尝试从变量 x
中获取 $x
的值,并将此值作为参数传递给 SQL 查询,从而消除了 SQL 注入的风险。下面您可以看到如何传递包含参数的字典
data = db.select("select * from Person where name = $x", {"x" : "Susan"})
这种将参数传递给 SQL 查询的方法非常灵活,不仅允许使用单个变量,还可以使用任何 Python 表达式。为了指定表达式,您需要在 $ 符号后将其括在括号中。
data = db.select("select * from Person where name = $(x.lower()) and age > $(y + 2)")
所有参数都可以使用 Pony 的统一方式传递到查询中,与 DBAPI 提供程序无关,使用 $
符号。在上面的示例中,我们将 name
和 age
参数传递到查询中。
可以在查询文本中包含 Python 表达式,例如
x = 10
a = 20
b = 30
db.execute("SELECT * FROM Table1 WHERE column1 = $x and column2 = $(a + b)")
如果您需要在查询中将 $ 符号用作字符串文字,则需要使用另一个 $ 对其进行转义(连续放置两个 $ 符号:$$)。
自定义连接行为¶
您可以使用 db.on_connect()
装饰器执行一些查询来指定您的连接(即 pragma)。
db = Database()
# entities declaration
@db.on_connect(provider='sqlite')
def sqlite_case_sensitivity(db, connection):
cursor = connection.cursor()
cursor.execute('PRAGMA case_sensitive_like = OFF')
db.bind(**options)
db.generate_mapping(create_tables=True)
使用以下代码,每个新的 sqlite 连接都会调用此函数。此示例展示了如何为 sqlite 恢复旧的区分大小写的 like。
数据库统计信息¶
Database
对象会保留执行查询的统计信息。您可以检查哪些查询执行得更频繁,执行它们花费了多长时间,以及其他一些参数。有关更多详细信息,请查看 API 参考中的 QueryStat
类。