Python 现代开发学习笔记

(八)把筛选条件落实为同一组查询

1. 参数进入 SQL 的位置

# 续写同一文件:catalog_project/src/cataloghub/storage.py
def query(connection, q="", finished="all", tag="", page=1, size=3):
    conditions, values = ["instr(lower(title),lower(?))>0"], [q]
    if finished != "all":
        conditions.append("finished=?")
        values.append(int(finished))
    if tag:
        # json_each 将这本书的标签数组展开,value 是其中一项标签。
        conditions.append(
            "EXISTS(SELECT 1 FROM json_each(books.tags_json) WHERE value=?)"
        )
        values.append(tag)
    where = " AND ".join(conditions)
    count = connection.execute(
        "SELECT count(*) FROM books WHERE " + where, values
    ).fetchone()[0]
    rows = connection.execute(
        "SELECT * FROM books WHERE " + where + " ORDER BY source_id LIMIT ? OFFSET ?",
        [*values, size, (page - 1) * size],
    ).fetchall()
    return {
        "total": count,
        "page": page,
        "size": size,
        "pages": max(1, (count + size - 1) // size),
        "items": [public(row) for row in rows],
    }


def public(row):
    return {
        "source_id": row["source_id"],
        "title": row["title"],
        "finished": bool(row["finished"]),
        "tags": json.loads(row["tags_json"]),
        "updated_run": row["updated_run"],
    }

SQL 结构来自程序,用户输入放进 ? 参数。书名使用 instr(lower(title), lower(?)) 判断是否包含关键词;输入 % 时就查找百分号本身。标签列是 JSON 文本,json_each 把当前书的数组逐项展开,EXISTS 判断是否有与参数完全相同的一项。

例如 b102 保存 ["数值"],展开后有一行 value="数值";b104 的数组展开为 "网络",不会匹配。json_each 的列和展开行为可查 SQLite JSON 函数文档。

先展开 b102 和 b104 的标签数组,再用 value 精确比较,最后与其他筛选条件组合

2. 手算计数、页数与偏移量

六本书中有四本未读,按编号排成 b101、b103、b104、b106。每页三本,第二页先跳过三本:offset=(page-1)*size=3,因此只剩 b106。页数取向上整除:(total+size-1)//size=2。

计数和取本页记录使用相同的 where。Web 依赖会显式开始读取事务,让它们看到同一个数据库快照。采集进程在旁边提交新书时,这一次响应中的总数与记录仍来自同一份读取视图。

把四本未读书排序,依次算出总数、页数和第二页偏移,再保留原条件生成翻页链接

笔记正文与全部题解 · Ctrl / ⌘ K