文章目录
13.4 apsw,一个高级的 sqlite 驱动程序
该apsw_ext模块包含一个适合与 apsw sqlite 驱动程序一起使用的数据库类。
APSW 项目页面:https 😕/github.com/rogerbinns/apsw
APSW 是一个非常简洁的库,它在 SQLite 的 C 接口之上提供了一个精简的包装器,从而可以使用 SQLite 的所有高级功能。
以下是使用 APSW 的几个原因,摘自文档:
- APSW 提供了 SQLite 的所有功能,包括虚拟表、虚拟文件系统、blob i/o、备份和文件控制。
- 可以跨线程共享连接,而无需任何额外的锁定。
- 事务由您的代码显式管理。
- APSW 可以处理嵌套事务。
- Unicode 被正确处理。
- APSW 更快。
有关 apsw 和 pysqlite 之间差异的更多信息,请查看apsw 文档。
13.4.1 如何使用 APSW 数据库
from apsw_ext import *
db = APSWDatabase(':memory:')
class BaseModel(Model):
class Meta:
database = db
class SomeModel(BaseModel):
col1 = CharField()
col2 = DateTimeField()
13.4.2 apsw_ext API 说明
APSWDatabase扩展SqliteExtDatabase并继承了其高级功能。
class APSWDatabase(database,**connect_kwargs )
参数:
- database ( string ) – sqlite 数据库的文件名
- connect_kwargs – 打开连接时传递给 apsw 的关键字参数
register_module( mod_name , mod_inst )
提供一种全局注册模块的方法。有关详细信息,请参阅有关虚拟表的文档。
参数:
- mod_name ( string ) – 用于模块的名称
- mod_inst ( object ) – 实现Virtual Table接口的对象
unregister_module( mod_name )
注销一个模块。
参数: 模组名称( string ) – 用于模块的名称
笔记
请务必使用模块中Field定义的子类apsw_ext ,因为它们将正确处理调整数据类型以进行存储。
例如,不要使用peewee.DateTimeField,请确保您正在导入和使用playhouse.apsw_ext.DateTimeField.
13.5 Sqlcipher 后端
笔记
尽管此扩展的代码很短,但尚未经过适当的同行评审,并且可能引入了漏洞。
另请注意,此代码依赖于sqlcipher3(python 绑定)和sqlcipher,其中的代码也可能存在漏洞,但由于这些是广泛使用的加密模块,我们可以预期那里的“短零日”。
13.5.1 sqlcipher_ext API 说明
class SqlCipherDatabase(database, passphrase, **kwargs)
SqliteDatabase存储加密数据库的子类。它没有使用标准sqlite3后端,而是使用sqlcipher3 : sqlcipher的python 包装器,而后者又是一个加密包装器sqlite3,因此 API与’s 相同,SqliteDatabase除了对象构造参数:
参数:
- database – 要打开 [或创建] 的加密数据库文件名的路径。
- passphrase – 数据库加密密码:至少应为 8 个字符长,但强烈建议在您的实现中强制执行更好的密码强度 标准。
如果该database文件不存在,它将通过从passhprase.
尝试打开现有数据库时,passhprase应与创建时使用的数据库相同。如果密码不正确,首次尝试访问数据库时将引发错误。
rekey(passphrase)
参数: passphrase( str ) – 数据库的新密码。
更改数据库的密码。
笔记
可以使用许多扩展 PRAGMA 来配置 SQLCipher。可以在SQLCipher 文档中找到 PRAGMA 列表及其描述。
例如,指定密钥派生的 PBKDF2 迭代次数(SQLCipher 3.x 中为 64K,SQLCipher 4.x 中默认为 256K):
# Use 1,000,000 iterations.
db = SqlCipherDatabase('my_app.db', pragmas={'kdf_iter': 1000000})
要使用 16KB 的密码页面大小和 10,000 个页面的缓存大小:
db = SqlCipherDatabase('my_app.db', passphrase='secret!!!', pragmas={
'cipher_page_size': 1024 * 16,
'cache_size': 10000}) # 10,000 16KB pages, or 160MB.
提示用户输入密码的示例:
db = SqlCipherDatabase(None)
class BaseModel(Model):
"""Parent for all app's models"""
class Meta:
# We won't have a valid db until user enters passhrase.
database = db
# Derive our model subclasses
class Person(BaseModel):
name = TextField(primary_key=True)
right_passphrase = False
while not right_passphrase:
db.init(
'testsqlcipher.db',
passphrase=get_passphrase_from_user())
try: # Actually execute a query against the db to test passphrase.
db.get_tables()
except DatabaseError as exc:
# This error indicates the password was wrong.
if exc.args[0] == 'file is encrypted or is not a database':
tell_user_the_passphrase_was_wrong()
db.init(None) # Reset the db.
else:
raise exc
else:
# The password was correct.
right_passphrase = True
另见:一个稍微复杂的例子。
13.6 Postgresql 扩展
postgresql 扩展模块提供了许多“postgres-only”功能,目前:
- json 支持,包括Postgres 9.4 的jsonb。
- hstore 支持
- server-side cursors 服务器端游标
- full-text search 全文检索
- ArrayField字段类型,用于存储数组。
- HStoreField字段类型,用于存储键/值对。
- IntervalField字段类型,用于存储
timedelta
对象。 - JSONField字段类型,用于存储 JSON 数据。
- BinaryJSONField 数据类型的
jsonb
JSON字段类型。 - TSVectorField字段类型,用于存储全文搜索数据。
- DateTimeTZField字段类型,时区感知的日期时间字段。
将来我想添加对更多 postgresql 功能的支持。如果您希望添加某个特定功能,请 打开 Github 问题。
警告
为了开始使用下面描述的功能,您需要使用扩展PostgresqlExtDatabase
类而不是PostgresqlDatabase
下面的代码将假设您使用以下数据库和基本模型:
from playhouse.postgres_ext import *
ext_db = PostgresqlExtDatabase('peewee_test', user='postgres')
class BaseExtModel(Model):
class Meta:
database = ext_db
13.6.1 JSON 支持
peewee 对 Postgres 的原生 JSON 数据类型有基本的支持,格式为 JSONField. 从 2.4.7 版本开始,peewee 还支持 Postgres 9.4 二进制 jsonjsonb类型,通过BinaryJSONField.
警告
Postgres 从 9.2 开始原生支持 JSON 数据类型(在 9.3 中完全支持)。要使用此功能,您必须使用正确版本的 Postgres 和psycopg2 2.5 或更高版本。
要使用BinaryJSONField具有许多性能和查询优势的 ,您必须具有 Postgres 9.4 或更高版本。
笔记
您必须确保您的数据库是一个实例 PostgresqlExtDatabase才能使用JSONField。
下面是一个示例,说明如何使用 JSON 字段声明模型:
import json
import urllib2
from playhouse.postgres_ext import *
db = PostgresqlExtDatabase('my_database')
class APIResponse(Model):
url = CharField()
response = JSONField()
class Meta:
database = db
@classmethod
def request(cls, url):
fh = urllib2.urlopen(url)
return cls.create(url=url, response=json.loads(fh.read()))
APIResponse.create_table()
# Store a JSON response.
offense = APIResponse.request('http://crime-api.com/api/offense/')
booking = APIResponse.request('http://crime-api.com/api/booking/')
# Query a JSON data structure using a nested key lookup:
offense_responses = APIResponse.select().where(
APIResponse.response['meta']['model'] == 'offense')
# Retrieve a sub-key for each APIResponse. By calling .as_json(), the
# data at the sub-key will be returned as Python objects (dicts, lists,
# etc) instead of serialized JSON.
q = (APIResponse
.select(
APIResponse.data['booking']['person'].as_json().alias('person'))
.where(APIResponse.data['meta']['model'] == 'booking'))
for result in q:
print(result.person['name'], result.person['dob'])
其BinaryJSONField工作原理与常规相同,支持相同的操作JSONField,但提供了几个额外的操作来测试遏制。使用二进制 json 字段,您可以测试您的 JSON 数据是否包含其他部分 JSON 结构 ( contains(), contains_any(), contains_all()),或者它是否是较大 JSON 文档的子集 ( contained_by())。
有关更多示例,请参阅下面的JSONField和 BinaryJSONFieldAPI 文档。
13.6.2 hstore 支持
Postgresql hstore 是一个嵌入式键/值存储。使用 hstore,您可以将任意键/值对与结构化关系数据一起存储在数据库中。
要使用hstore,您需要在实例化时指定一个附加参数PostgresqlExtDatabase:
# Specify "register_hstore=True":
db = PostgresqlExtDatabase('my_db', register_hstore=True)
目前该postgres_ext模块支持以下操作:
- 存储和检索任意字典
- 按键或部分字典过滤
- 更新/添加一个或多个键到现有字典
- 从现有字典中删除一个或多个键
- 选择键、值或 zip 键和值
- 检索一段键/值
- 测试密钥是否存在
- 测试一个键是否具有非 NULL 值