【Python百日进阶-Web开发-Peewee】Day254 - Peewee 增加记录

八、查询

http://docs.peewee-orm.com/en/latest/peewee/querying.html
本节将介绍通常在关系数据库上执行的基本 CRUD 操作:

  • Model.create(), 用于执行INSERT查询。
  • Model.save()和Model.update(), 用于执行UPDATE 查询。
  • Model.delete_instance()和Model.delete(), 用于执行 DELETE查询。
  • Model.select(),用于执行SELECT查询。

笔记

还有大量来自 Postgresql 练习网站的示例查询。查询示例文档中列出了示例

8.1 创建新记录

您可以使用它Model.create()来创建一个新的模型实例。此方法接受关键字参数,其中键对应于模型字段的名称。返回一个新实例,并将一行添加到表中。

>>> User.create(username='Charlie')
<__main__.User object at 0x2529350>

这将在数​​据库中插入一个新行。主键将被自动检索并存储在模型实例中。

或者,您可以以编程方式构建模型实例,然后调用 save():

>>> user = User(username='Charlie')
>>> user.save()  # save() returns the number of rows modified.
1
>>> user.id
1
>>> huey = User()
>>> huey.username = 'Huey'
>>> huey.save()
1
>>> huey.id
2

当模型有外键时,可以在新建记录时直接将模型实例赋值给外键字段。

>>> tweet = Tweet.create(user=huey, message='Hello!')

您还可以使用相关对象的主键的值:

>>> tweet = Tweet.create(user=2, message='Hello again!')

如果您只是想插入数据而不需要创建模型实例,您可以使用Model.insert():

>>> User.insert(username='Mickey').execute()
3

执行插入查询后,返回新行的主键。

笔记

有几种方法可以加快批量插入操作。查看批量插入配方部分了解更多信息。

8.2 批量插入

有几种方法可以快速加载大量数据。天真的方法是简单地调用Model.create()一个循环:

data_source = [
    {'field1': 'val1-1', 'field2': 'val1-2'},
    {'field1': 'val2-1', 'field2': 'val2-2'},
    # ...
]

for data_dict in data_source:
    MyModel.create(**data_dict)

由于以下几个原因,上述方法很慢:

  • 如果您没有将循环包装在事务中,则每次调用都 create()发生在其自己的事务中。这将是非常缓慢的!
  • 有相当数量的 Python 逻辑阻碍了你的工作,每个逻辑都 InsertQuery必须生成并解析为 SQL。
  • 这是您发送到数据库进行解析的大量数据(就 SQL 的原始字节而言)。
  • 我们正在检索最后一个插入 id,这在某些情况下会导致执行额外的查询。
    你可以通过简单地将它包装在一个事务中来获得显着的加速 atomic()。
# This is much faster.
with db.atomic():
    for data_dict in data_source:
        MyModel.create(**data_dict)

上面的代码仍然存在第 2、3 和 4 点的问题。我们可以通过使用insert_many(). 此方法接受元组或字典列表,并在单个查询中插入多行:

data_source = [
    {'field1': 'val1-1', 'field2': 'val1-2'},
    {'field1': 'val2-1', 'field2': 'val2-2'},
    # ...
]

# Fastest way to INSERT multiple rows.
MyModel.insert_many(data_source).execute()

该insert_many()方法还接受行元组列表,前提是您还指定了相应的字段:

# We can INSERT tuples as well...
data = [('val1-1', 'val1-2'),
        ('val2-1', 'val2-2'),
        ('val3-1', 'val3-2')]

# But we need to indicate which fields the values correspond to.
MyModel.insert_many(data, fields=[MyModel.field1, MyModel.field2]).execute()

将批量插入包装在事务中也是一个好习惯:

# You can, of course, wrap this in a transaction as well:
with db.atomic():
    MyModel.insert_many(data, fields=fields).execute()

笔记

SQLite 用户在使用批量插入时应该注意一些警告。具体来说,您的 SQLite3 版本必须是 3.7.11.0 或更高版本才能利用批量插入
API。此外,默认情况下,SQLite 将 SQL 查询中绑定变量的数量限制999为 3.32.0 (2020-05-22) 之前的
SQLite 版本和 3.32.0 之后的 SQLite 版本的 32766。

8.2.1 批量插入行

根据数据源中的行数,您可能需要将其分成块。特别是 SQLite 通常限制每个查询 999 或 32766 个 变量(批量大小将是 999 // 行长度或 32766 // 行长度)。

您可以编写一个循环来将您的数据批处理成块(在这种情况下, 强烈建议您使用事务):

# Insert rows 100 at a time.
with db.atomic():
    for idx in range(0, len(data_source), 100):
        MyModel.insert_many(data_source[idx:idx+100]).execute()

Peewee 附带了一个chunked()辅助函数,您可以使用它来 有效地将通用迭代分块为一系列批量大小的迭代:

from peewee import chunked

# Insert rows 100 at a time.
with db.atomic():
    for batch in chunked(data_source, 100):
        MyModel.insert_many(batch).execute()

8.2.2 备择方案

该Model.bulk_create()方法的行为很像 Model.insert_many(),但它接受要插入的未保存模型实例的列表,并且它可以选择接受批量大小参数。要使用bulk_create()API:

# Read list of usernames from a file, for example.
with open('user_list.txt') as fh:
    # Create a list of unsaved User instances.
    users = [User(username=line.strip()) for line in fh.readlines()]

# Wrap the operation in a transaction and batch INSERT the users
# 100 at a time.
with db.atomic():
    User.bulk_create(users, batch_size=100)

笔记

如果您使用的是 Postgresql(支持该RETURNING子句),那么以前未保存的模型实例将自动填充其新的主键值。

此外,Peewee 还提供Model.bulk_update(),可以有效地更新模型列表中的一个或多个列。例如:

# First, create 3 users with usernames u1, u2, u3.
u1, u2, u3 = [User.create(username='u%s' % i) for i in (1, 2, 3)]

# Now we'll modify the user instances.
u1.username = 'u1-x'
u2.username = 'u2-y'
u3.username = 'u3-z'

# Update all three users with a single UPDATE query.
User.bulk_update([u1, u2, u3], fields=[User.username])

笔记

对于大型对象列表,您应该指定一个合理的 batch_size 并将调用包装到bulk_update()with
Database.atomic():

with database.atomic():
    User.bulk_update(list_of_users, fields=['username'], batch_size=50)

或者,您可以使用Database.batch_commit()帮助程序来处理批处理大小的事务中的行块。此方法还为除 Postgresql 之外的数据库提供了一种解决方法,当必须获取新创建的行的主键时。

# List of row data to insert.
row_data = [{'username': 'u1'}, {'username': 'u2'}, ...]

# Assume there are 789 items in row_data. The following code will result in
# 8 total transactions (7x100 rows + 1x89 rows).
for row in db.batch_commit(row_data, 100):
    User.create(**row)

8.2.3 从另一个表批量加载

如果您要批量加载的数据存储在另一个表中,您还可以创建源为SELECT查询的INSERT查询。使用 方法:Model.insert_from()

res = (TweetArchive
       .insert_from(
           Tweet.select(Tweet.user, Tweet.message),
           fields=[TweetArchive.user, TweetArchive.message])
       .execute())

上面的查询等价于下面的 SQL:

INSERT INTO "tweet_archive" ("user_id", "message")
SELECT "user_id", "message" FROM "tweet";
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岳涛@心馨电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值