惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy International News Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Attack and Defense Labs
Attack and Defense Labs
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
Cloudbric
Cloudbric
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Help Net Security
Help Net Security
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
N
News and Events Feed by Topic
T
Tenable Blog
S
Security @ Cisco Blogs
N
News and Events Feed by Topic
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
V
Visual Studio Blog
P
Proofpoint News Feed
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
L
LangChain Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东

冰屋

在TeamSpeak内搭建网易云音乐bot – 冰屋 Linux to go — Rime输入法 – 冰屋 Linux to go — 配置和初体验 – 冰屋 【杂谈】如何快速备考托福 – 冰屋 使用自建N2N加速P2P联机游戏 – 冰屋 FastAPI与SQLModel – 冰屋 FastAPI快速上手 – 冰屋 看不了番剧?自动化你的番剧订阅流程吧! – 冰屋 你好,世界 – 冰屋
SQLModel快速上手 – 冰屋
2024-11-29 · via 冰屋
  • 一个用于与SQL数据库交互的库
  • 基于类型注解
  • 与FastAPI兼容性非常高,因为这俩库是一人写的

安装

pip install sqlmodel

完了

创建模型与表

创建模型

假设你需要创建一个名为hero的表,包含以下字段:

  • id
  • name
  • secret_name
  • age

那么你可以这么写:

from sqlmodel import Field, SQLModel, create_engine 
# create_engine将会在之后的代码中用到

class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True) 
    name: str 
    secret_name: str 
    age: int | None = None

假设你有好好学基础Python课程,知道一些基础语法,但你仍然可能对上述代码有一些小小的困惑,它可能包含了一些你不清楚的语法,这里稍微做一些解释:

  • name: str:这里的:类型标注的一部分,整体而言,这里就是在告诉Python(以及你的IDE)变量namestr类型的。关于类型标注,你还可以参考Python 类型提示简介 – FastAPI
  • id: int | None:这里除了:还出现了|,这与 C++|差别不大,可以理解为。就是说,变量id可能是int也可能是None

table=True代表了这个类将会被当作表处理。如果不设置这项,那SQLModel不会将此类和数据库中的表对应,之后你也不能创建hero表了

在上述代码中,我们将变量id设为int或是None,因为idhero的自增主键,在创建时不需要人为指定,因此在创建时其值可能是NoneSQLModel在实际往表中添加记录时会帮你处理这个问题。当然,你也需要使用Field()来指定这是个主键

你可能看出来了,这里的namesecret_name必须在创建hero实例时指定,而age不需要

创建数据库中的表

要使用简单方便的sqlite数据库,你可以用以下方式创建数据库引擎:

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True)

当然,你也可以换成MySQL数据库,那么你需要这么写:

mysql_url = f"mysql+pymysql://{user}:{password}@{host}/{db_name}?charset={charset}"  
# db_name是特定的数据库的名字
# 常见的charset可能形如"utf8mb4"
engine = create_engine(mysql_url, echo=True)

无论使用什么数据库,现在我们都获得了一个连接数据库的引擎engine。由于我们将echo设为了TrueSQLModel会在执行任何SQL语句时都输出对应语句。当然,在生产环境时你不需要他,只需要把他删掉即可,默认值为False

最后,你终于可以创建这个表了:

SQLModel.metadata.create_all(engine)

这句语句执行完毕后,数据库内就会出现hero表了

噢,我猜聪明的你肯定在想,为什么我没有往这个create_all里传任何表类作为参数,但是他还是成功创建了这个表?

事实上,SQLModel会记录你所创建的所有继承于SQLModel类的子类,然后他就能知道创建哪些表

这很重要,因为有时候你会将定义模型创建表放在两个文件里。这时,你就需要在创建表前先import入对应模型,然后再使用create_all函数

往表内插入数据

hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
hero_2 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)
# 数据来自SQLModel文档,略有删改

session = Session(engine)

session.add(hero_1)
session.add(hero_2)

session.commit()

session.close()
  • hero_1hero_2都是Hero类的实例,很好理解
  • session是与数据库的对话,用于处理这组关于数据库的操作
  • 通过session.add(),你可以往数据库里添加数据
  • session.commit()提交了这些数据,直到此时,数据库内的数据才会真的有所更改
  • 最后,使用session.close()关闭会话

当然,你也可以使用with语句块来自动进行session的关闭:

with Session(engine) as session:
    session.add(hero_1)
    session.add(hero_2)
    session.commit()

session.commit()后,如果你直接再次访问hero_1,其不会包含数据,因为他需要刷新

这会在你调用了任何hero_1的字段(例如hero_1.id)过后被隐式自动刷新。你也可以使用session.refresh(hero_1)来刷新,使其包含了最新的数据

删改查

在之前的模型基础上:

from sqlmodel import Session, select

with Session(engine) as session:
    statement = select(Hero)
    results = session.exec(statement)
    for hero in results:
        print(hero)

在这里:

  • select()创建了一个statement,这个statement需要放到session.exec()里执行
  • 这里返回的results是一个可迭代对象,而非一个列表。如果你直接需要一个列表,可以使用`session.exec().all()
  • 如果你只需要一个对象,可以使用results.first()

如果你需要某些特定的记录,你可以这么做:

from sqlmodel import Session, select, where

with Session(engine) as session:
    statement = select(Hero).where(Hero.name == "Deadpond")
    results = session.exec(statement)
    for hero in results:
        print(hero)

在这里:

  • where()接受的是一个表达式,而非单纯的传参
  • 如果你单纯只需要通过id查找一个对象,可以使用session.get(Hero, hero_id)

简单的更改对象,然后保存即可

with Session(engine) as session:
    hero = session.get(Hero, hero_id)

    hero.age = 16
    session.add(hero)
    session.commit()

    # 如果你需要在此之后继续访问这个hero对象,你就需要...
    session.refresh(hero)
    # 然后你就可以...
    print(hero)

简单的使用session.delete()即可

with Session(engine) as session:
    hero = session.get(Hero, hero_id)
    session.delete(hero)
    session.commit()