快速入门#

您好,欢迎来到十二分钟快速入门教程。

连接到数据库#

首先,您需要导入 dataset 包 :)

import dataset

要连接到数据库,您需要通过其 URL 来识别它,它基本上是一个字符串,格式为 "dialect://user:password@host/dbname"。以下是一些针对不同数据库后端的示例

# connecting to a SQLite database
db = dataset.connect('sqlite:///mydatabase.db')

# connecting to a MySQL database with user and password
db = dataset.connect('mysql://user:password@localhost/mydatabase')

# connecting to a PostgreSQL database
db = dataset.connect('postgresql://scott:tiger@localhost:5432/mydatabase')

也可以将 URL 定义为名为 DATABASE_URL 的环境变量,这样您就可以在没有显式传递 URL 的情况下初始化数据库连接。

db = dataset.connect()

根据您使用的数据库,您可能还需要安装数据库绑定以支持该数据库。SQLite 包含在 Python 核心库中,但 PostgreSQL 需要安装 psycopg2。MySQL 可以通过安装 mysql-db 驱动程序来启用。

存储数据#

要存储一些数据,您需要获取对表的引用。您无需担心表是否已存在,因为 dataset 会自动创建它。

# get a reference to the table 'user'
table = db['user']

现在,将数据存储到表中只需一个函数调用。只需将一个 dict 传递给 insert。请注意,您无需创建 nameage 列 - dataset 会自动完成此操作。

# Insert a new record.
table.insert(dict(name='John Doe', age=46, country='China'))

# dataset will create "missing" columns any time you insert a dict with an unknown key
table.insert(dict(name='Jane Doe', age=37, country='France', gender='female'))

更新现有条目也很容易。

table.update(dict(name='John Doe', age=47), ['name'])

作为第二个参数给出的过滤器列列表使用第一列中的值进行过滤。如果您不想更新特定值,只需使用自动生成的 id 列。

使用事务#

您可以将一组数据库更新分组到一个事务中。在这种情况下,所有更新将一次性提交,或者在出现异常时,所有更新都将回滚。事务通过上下文管理器支持,因此可以通过 with 语句使用。

with dataset.connect() as tx:
    tx['user'].insert(dict(name='John Doe', age=46, country='China'))

您可以通过显式调用方法 begin()commit()rollback() 来获得相同的功能。

db = dataset.connect()
db.begin()
try:
    db['user'].insert(dict(name='John Doe', age=46, country='China'))
    db.commit()
except:
    db.rollback()

嵌套事务也受支持。

db = dataset.connect()
with db as tx1:
    tx1['user'].insert(dict(name='John Doe', age=46, country='China'))
    with db as tx2:
        tx2['user'].insert(dict(name='Jane Doe', age=37, country='France', gender='female'))

检查数据库和表#

在处理未知数据库时,我们可能希望首先检查其结构。为了开始探索,让我们找出存储在数据库中的表。

>>> print(db.tables)
[u'user']

现在,让我们列出表 user 中可用的所有列。

>>> print(db['user'].columns)
[u'id', u'country', u'age', u'name', u'gender']

使用 len(),我们可以获取表中的总行数。

>>> print(len(db['user']))
2

从表中读取数据#

现在让我们从表中获取一些真实数据。

users = db['user'].all()

如果我们只想遍历表中的所有行,我们可以省略 all()

for user in db['user']:
   print(user['age'])

我们可以使用 find()find_one() 搜索特定条目。

# All users from China
chinese_users = table.find(country='China')

# Get a specific user
john = table.find_one(name='John Doe')

# Find multiple at once
winners = table.find(id=[1, 3, 7])

# Find by comparison operator
elderly_users = table.find(age={'>=': 70})
possible_customers = table.find(age={'between': [21, 80]})

# Use the underlying SQLAlchemy directly
elderly_users = table.find(table.table.columns.age >= 70)

有关复杂过滤器的详细信息,请参阅 高级过滤器

使用 distinct(),我们可以获取在一列或多列中具有唯一值的行的集合。

# Get one user per country
db['user'].distinct('country')

最后,您可以使用 row_type 参数来选择结果将以哪种数据类型返回。

import dataset
from stuf import stuf

db = dataset.connect('sqlite:///mydatabase.db', row_type=stuf)

现在,内容将以 stuf 对象返回(基本上,dict 对象,其元素可以通过属性 (item.name) 和索引 (item['name']) 访问)。

运行自定义 SQL 查询#

当然,您使用数据库的主要原因是您希望使用 SQL 查询的全部功能。以下是如何使用 dataset 运行它们。

result = db.query('SELECT country, COUNT(*) c FROM user GROUP BY country')
for row in result:
   print(row['country'], row['c'])

query() 方法也可以用于访问底层的 SQLAlchemy 核心 API,它允许以编程方式构建更复杂的查询。

table = db['user'].table
statement = table.select(table.c.name.like('%John%'))
result = db.query(statement)

dataset 的局限性#

dataset 的目标是通过以 Pythonic 方式表达一些相对基本的运算来简化基本的数据库操作。这种方法的缺点是,随着应用程序变得越来越复杂,您可能需要访问更高级的操作,并被迫切换到使用 SQLAlchemy 本身,而没有 dataset 层(相反,您可能希望使用 SQLAlchemy 的 ORM)。

当那一刻到来时,接受它。SQLAlchemy 是一段很棒的 Python 代码,它将为您提供对所有 SQL 函数的惯用访问。

一些在 dataset 中未公开的 SQL 特定方面,并且被认为超出项目范围,包括

  • 表之间的外键关系,以及以惯用 Python 方式表达一对多和多对多关系。

  • Python 封装的 JOIN 查询。

  • 创建数据库或管理 DBMS 软件。

  • 支持 Python 2.x

还有一些功能可能在将来支持起来很酷,但这需要大量的工程工作。

  • 异步操作

  • 数据库本地的 UPSERT 语义