【Python百日进阶-Web开发-Peewee】Day245 - 数据库 SQLite

文章介绍了如何使用Peewee库连接和配置SQLite数据库,包括参数声明如journal_mode和cache_size,推荐的设置,以及用户自定义函数、事务锁定模式和APSW高级SQLite驱动程序的使用。
摘要由CSDN通过智能技术生成

6.4 使用 SQLite

要连接到 SQLite 数据库,我们将使用SqliteDatabase. 第一个参数是包含数据库的文件名,或 ':memory:'用于创建内存数据库的字符串。在数据库文件名之后,您可以指定列表或编译指示或任何其他任意sqlite3 参数。

sqlite_db = SqliteDatabase('my_app.db', pragmas={'journal_mode': 'wal'})

class BaseModel(Model):
    """A base model that will use our Sqlite database."""
    class Meta:
        database = sqlite_db

class User(BaseModel):
    username = TextField()
    # etc, etc

Peewee 包含一个SQLite 扩展模块,它提供了许多 SQLite 特定的功能,例如全文搜索、 json 扩展支持等等。如果您想使用这些很棒的功能,请使用SqliteExtDatabase模块中的playhouse.sqlite_ext:

from playhouse.sqlite_ext import SqliteExtDatabase

sqlite_db = SqliteExtDatabase('my_app.db', pragmas={
    'journal_mode': 'wal',  # WAL-mode.
    'cache_size': -64 * 1000,  # 64MB cache.
    'synchronous': 0})  # Let the OS manage syncing.

6.4.1 参数声明

PRAGMASQLite 允许通过语句(SQLite 文档)对许多参数进行运行时配置 。这些语句通常在创建新的数据库连接时运行。要针对新连接运行一个或多个PRAGMA语句,可以将它们指定为字典或包含 pragma 名称和值的 2 元组列表:

db = SqliteDatabase('my_app.db', pragmas={
    'journal_mode': 'wal',
    'cache_size': 10000,  # 10000 pages, or ~40MB
    'foreign_keys': 1,  # Enforce foreign-key constraints
})

PRAGMA 也可以使用 pragma()方法或对象上公开的特殊属性动态配置SqliteDatabase:

# Set cache size to 64MB for *current connection*.
db.pragma('cache_size', -1024 * 64)

# Same as above.
db.cache_size = -1024 * 64

# Read the value of several pragmas:
print('cache_size:', db.cache_size)
print('foreign_keys:', db.foreign_keys)
print('journal_mode:', db.journal_mode)
print('page_size:', db.page_size)

# Set foreign_keys pragma on current connection *AND* on all
# connections opened subsequently.
db.pragma('foreign_keys', 1, permanent=True)

注意力

使用该方法设置的 Pragma
pragma(),默认情况下,在连接关闭后不会持续存在。要将编译指示配置为在打开连接时运行,请指定permanent=True.

笔记

PRAGMA 设置的完整列表、它们的含义和可接受的值可以在 SQLite 文档中找到: http:
//sqlite.org/pragma.html

6.4.2 推荐设置

以下设置是我与 SQLite 一起用于典型 Web 应用程序数据库的设置。

参数推荐设置解释
journal_mode沃尔让读者和作家共存
cache_size-1 * data_size_kb以 KiB 为单位设置页面缓存大小,例如 -32000 = 32MB
foreign_keys1强制外键约束
ignore_check_constraints0强制 CHECK 约束
synchronous0让操作系统处理 fsync(谨慎使用)
使用上述选项的示例数据库:
db = SqliteDatabase('my_app.db', pragmas={
    'journal_mode': 'wal',
    'cache_size': -1 * 64000,  # 64MB
    'foreign_keys': 1,
    'ignore_check_constraints': 0,
    'synchronous': 0})

6.4.3 用户自定义函数

SQLite 可以使用用户定义的 Python 代码进行扩展。该类 SqliteDatabase支持三种类型的用户定义扩展:

  • 函数 - 接受任意数量的参数并返回单个值。
  • 聚合 - 聚合来自多行的参数并返回单个值。
  • 排序规则 - 描述如何对某些值进行排序。

笔记

如需更多扩展支持,请参阅模块SqliteExtDatabase中的。playhouse.sqlite_ext

用户定义函数示例:

db = SqliteDatabase('analytics.db')

from urllib.parse import urlparse

@db.func('hostname')
def hostname(url):
    if url is not None:
        return urlparse(url).netloc

# Call this function in our code:
# The following finds the most common hostnames of referrers by count:
query = (PageView
         .select(fn.hostname(PageView.referrer), fn.COUNT(PageView.id))
         .group_by(fn.hostname(PageView.referrer))
         .order_by(fn.COUNT(PageView.id).desc()))

示例用户定义的聚合:

from hashlib import md5

@db.aggregate('md5')
class MD5Checksum(object):
    def __init__(self):
        self.checksum = md5()

    def step(self, value):
        self.checksum.update(value.encode('utf-8'))

    def finalize(self):
        return self.checksum.hexdigest()

# Usage:
# The following computes an aggregate MD5 checksum for files broken
# up into chunks and stored in the database.
query = (FileChunk
         .select(FileChunk.filename, fn.MD5(FileChunk.data))
         .group_by(FileChunk.filename)
         .order_by(FileChunk.filename, FileChunk.sequence))

示例排序规则:

@db.collation('ireverse')
def collate_reverse(s1, s2):
    # Case-insensitive reverse.
    s1, s2 = s1.lower(), s2.lower()
    return (s1 < s2) - (s1 > s2)  # Equivalent to -cmp(s1, s2)

# To use this collation to sort books in reverse order...
Book.select().order_by(collate_reverse.collation(Book.title))

# Or...
Book.select().order_by(Book.title.asc(collation='reverse'))

示例用户定义的表值函数(请参阅TableFunction 和table_function)以获取更多详细信息:

from playhouse.sqlite_ext import TableFunction

db = SqliteDatabase('my_app.db')

@db.table_function('series')
class Series(TableFunction):
    columns = ['value']
    params = ['start', 'stop', 'step']

    def initialize(self, start=0, stop=None, step=1):
        """
        Table-functions declare an initialize() method, which is
        called with whatever arguments the user has called the
        function with.
        """
        self.start = self.current = start
        self.stop = stop or float('Inf')
        self.step = step

    def iterate(self, idx):
        """
        Iterate is called repeatedly by the SQLite database engine
        until the required number of rows has been read **or** the
        function raises a `StopIteration` signalling no more rows
        are available.
        """
        if self.current > self.stop:
            raise StopIteration

        ret, self.current = self.current, self.current + self.step
        return (ret,)

# Usage:
cursor = db.execute_sql('SELECT * FROM series(?, ?, ?)', (0, 5, 2))
for value, in cursor:
    print(value)

# Prints:
# 0
# 2
# 4

有关更多信息,请参阅:

  • SqliteDatabase.func()
  • SqliteDatabase.aggregate()
  • SqliteDatabase.collation()
  • SqliteDatabase.table_function()
  • 有关更多 SQLite 扩展,请参阅SQLite 扩展

6.4.4 设置事务的锁定模式

SQLite 事务可以以三种不同的模式打开:

  • Deferred(默认)- 仅在执行读取或写入时获取锁。第一次读取创建共享锁 ,第一次写入创建保留锁。因为锁的获取被推迟到实际需要时,另一个线程或进程可能会创建一个单独的事务并在当前线程上的 BEGIN 执行后写入数据库。
  • Immediate -立即获取保留锁 。在这种模式下,没有其他数据库可以写入数据库或打开立即或独占事务。但是,其他进程可以继续从数据库中读取。
  • Exclusive - 打开一个独占锁 ,防止所有(除了未提交的读取)连接访问数据库,直到事务完成。
    指定锁定模式的示例:
db = SqliteDatabase('app.db')

with db.atomic('EXCLUSIVE'):
    do_something()


@db.atomic('IMMEDIATE')
def some_other_function():
    # This function is wrapped in an "IMMEDIATE" transaction.
    do_something_else()

有关更多信息,请参阅 SQLite锁定文档。要了解有关 Peewee 中事务的更多信息,请参阅管理事务 文档。

6.4.5 APSW,高级 SQLite 驱动程序

Peewee 还附带了一个使用apsw 的备用 SQLite 数据库,一个高级 sqlite 驱动程序,一个高级 Python SQLite 驱动程序。有关 APSW 的更多信息,请 访问 APSW 项目网站。APSW 提供特殊功能,例如:

  • 虚拟表、虚拟文件系统、Blob I/O、备份和文件控制。
  • 可以跨线程共享连接,而无需任何额外的锁定。
  • 事务由您的代码显式管理。
  • Unicode 被正确处理。
  • APSW 比标准库 sqlite3 模块更快。
  • 将几乎整个 SQLite C API 暴露给您的 Python 应用程序。
    如果您想使用 APSW,请使用APSWDatabaseapsw_ext 模块中的:
from playhouse.apsw_ext import APSWDatabase

apsw_db = APSWDatabase('my_app.db')
以下是使用 FastAPI 中 Tortoise-ORM、SQLAlchemy 和 peewee 进行 ORM 查询的示例。 ## Tortoise-ORM ```python from fastapi import FastAPI from tortoise import fields from tortoise.contrib.fastapi import register_tortoise, HTTPNotFoundError from tortoise.models import Model from tortoise import Tortoise class User(Model): id = fields.IntField(pk=True) name = fields.CharField(50) email = fields.CharField(50) class Meta: table = "users" app = FastAPI() @app.on_event("startup") async def startup(): await Tortoise.init( db_url="sqlite://db.sqlite3", modules={"models": ["main"]} ) await Tortoise.generate_schemas() @app.on_event("shutdown") async def shutdown(): await Tortoise.close_connections() @app.get("/users") async def get_users(): users = await User.all() return users @app.get("/users/{user_id}") async def get_user(user_id: int): user = await User.get_or_none(id=user_id) if user is None: raise HTTPNotFoundError return user register_tortoise( app, db_url="sqlite://db.sqlite3", modules={"models": ["main"]}, generate_schemas=True, add_exception_handlers=True ) ``` ## SQLAlchemy ```python from fastapi import FastAPI from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) name = Column(String(50)) email = Column(String(50)) engine = create_engine("sqlite:///db.sqlite3") SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) app = FastAPI() @app.get("/users") async def get_users(): db = SessionLocal() users = db.query(User).all() db.close() return users @app.get("/users/{user_id}") async def get_user(user_id: int): db = SessionLocal() user = db.query(User).filter(User.id == user_id).first() db.close() if user is None: raise HTTPNotFoundError return user ``` ## peewee ```python from fastapi import FastAPI from peewee import SqliteDatabase, Model, CharField, IntegerField from playhouse.shortcuts import model_to_dict db = SqliteDatabase("db.sqlite3") class User(Model): id = IntegerField(primary_key=True) name = CharField() email = CharField() class Meta: database = db table_name = "users" app = FastAPI() @app.on_event("startup") def startup(): db.connect() db.create_tables([User]) @app.on_event("shutdown") def shutdown(): db.close() @app.get("/users") async def get_users(): users = [model_to_dict(user) for user in User.select()] return users @app.get("/users/{user_id}") async def get_user(user_id: int): user = User.get_or_none(User.id == user_id) if user is None: raise HTTPNotFoundError return model_to_dict(user) ``` 注意:以上示例中的代码仅用于演示 ORM 查询的基本用法,并且没有进行错误处理。在实际应用中,你应该根据需要添加适当的错误处理和安全性检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

岳涛@心馨电脑

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

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

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

打赏作者

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

抵扣说明:

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

余额充值