三周精通FastAPI:27 使用使用SQLModel操作SQL (关系型) 数据库
官网文档:https://fastapi.tiangolo.com/zh/tutorial/sql-databases/
SQL (关系型) 数据库¶
FastAPI不需要你使用SQL(关系型)数据库。
但是您可以使用任何您想要的关系型数据库。
这里我们将看到一个使用SQLModel的示例。
SQLModel是在SQLAlchemy和Pydantic的基础上构建的。它是由FastAPI的同一作者制作的,与需要使用SQL数据库的FastAPI应用程序完美匹配。
小贴士
你可以使用任何其他你想要的SQL或NoSQL数据库库(在某些情况下称为“ORM”),FastAPI不会强迫你使用任何东西。
由于SQLModel基于SQLAlchemy,您可以轻松使用SQLAlchemi支持的任何数据库(这使得它们也受SQLModel支持)您可以很容易地将其调整为任何SQLAlchemy支持的数据库,如:
- PostgreSQL
- MySQL
- SQLite
- Oracle
- Microsoft SQL Server,等等其它数据库
在此示例中,我们将使用SQLite,因为它使用单个文件并且 在Python中具有集成支持。因此,您可以复制此示例并按原样来运行它。
稍后,对于您的产品级别的应用程序,您可能会要使用像PostgreSQL这样的数据库服务器。
Tip
这儿有一个FastAPI和PostgreSQL的官方项目生成器,全部基于Docker,包括前端和更多工具:https://github.com/tiangolo/full-stack-fastapi-postgresql
这是一个非常简单而简短的教程,如果你想了解数据库、SQL或更高级的功能,请参阅SQLModel文档。
安装SQLModel
首先,确保创建虚拟环境,激活它,然后安装sqlmodel:
pip install sqlmodel
Successfully installed SQLAlchemy-2.0.36 sqlmodel-0.0.22
使用单个模型创建应用程序
我们将首先使用单个SQLModel模型创建该应用程序最简单的第一个版本。
稍后,我们将通过以下多种型号来提高它的安全性和多功能性。🤓
from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass Hero(SQLModel, table=True):id: int | None = Field(default=None, primary_key=True)name: str = Field(index=True)age: int | None = Field(default=None, index=True)secret_name: strsqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables():SQLModel.metadata.create_all(engine)def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:session.add(hero)session.commit()session.refresh(hero)return hero@app.get("/heroes/")
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}
创建模型
导入SQLModel并创建数据库模型:
from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass Hero(SQLModel, table=True):id: int | None = Field(default=None, primary_key=True)name: str = Field(index=True)age: int | None = Field(default=None, index=True)secret_name: str
🤓 其他版本和变体
Hero类与Pydantic模型非常相似(事实上,在下面,它实际上是一个Pydantic模式)。
存在一些差异:
- table=True告诉SQLModel这是一个表模型,它应该表示SQL数据库中的一个表,它不仅仅是一个数据模型(就像任何其他常规Pydantic类一样)。
- 字段(primary_key=True)告诉SQLModel id是SQL数据库中的主键(您可以在SQLModel文档中了解有关SQL主键的更多信息)。
- 通过将类型设置为int|None,SQLModel将知道该列在SQL数据库中应该是INTEGER,并且应该是NULLABLE。
- 字段(index=True)告诉SQLModel,它应该为该列创建SQL索引,这样在读取由该列筛选的数据时可以更快地在数据库中查找。
- SQLModel将知道声明为str的内容将是TEXT类型的SQL列(或VARCHAR,具体取决于数据库)。
创建引擎
SQLModel引擎(其下实际上是SQLAlchemy引擎)负责保存与数据库的连接。
您将有一个单一的引擎对象,用于所有代码连接到同一个数据库。
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)
使用check_same_thread=False允许FastAPI在不同线程中使用相同的SQLite数据库。这是必要的,因为一个请求可能会使用多个线程(例如在依赖关系中)。
别担心,根据代码的结构方式,我们将确保稍后每个请求使用一个SQLModel会话,这实际上是check_same_thread试图实现的。
创建表格
然后,我们添加一个函数,该函数使用SQLModel.media.create_all(engine)为所有表模型创建表。
def create_db_and_tables():SQLModel.metadata.create_all(engine)
创建会话依赖关系
会话是将对象存储在内存中并跟踪数据中所需的任何更改,然后使用引擎与数据库通信。
我们将使用yield创建一个FastAPI依赖关系,为每个请求提供一个新的Session。这就是确保我们每个请求使用单个会话的原因。🤓
然后,我们创建一个带注释的依赖项SessionDep,以简化将使用此依赖项的其余代码。
def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]
启动时创建数据库表
我们将在应用程序启动时创建数据库表。
app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()
在这里,我们在应用程序启动事件上创建表。
对于生产环境,您可能会使用在启动应用程序之前运行的迁移脚本。🤓
小贴士
SQLModel将有封装Alembic的迁移实用程序,但现在,您可以直接使用Alembic。
创建英雄库
因为每个SQLModel模型也是一个Pydantic模型,所以您可以在使用Pydantics模型的相同类型注释中使用它。
例如,如果你声明一个Hero类型的参数,它将从JSON正文中读取。
同样,您可以将其声明为函数的返回类型,然后数据的形状将显示在自动API文档UI中。
@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:session.add(hero)session.commit()session.refresh(hero)return hero
在这里,我们使用SessionDep依赖项(Session)将新的Hero添加到Session实例中,将更改提交到数据库中,刷新Hero中的数据,然后返回它。
读英雄库
我们可以使用select()从数据库中读取Heros。我们可以包含一个限制和偏移量来对结果进行分页。
@app.get("/heroes/")
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes
读一个英雄条目
我们可以读一个英雄。
@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero
如果不是英雄:
引发HTTPException(状态码=404,详细信息=“未找到英雄”)
删除英雄
我们也可以删除英雄。
@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}
运行应用程序
您可以运行该应用程序:
fastapi-dev-main.py

然后转到/docs UI,您将看到FastAPI正在使用这些模型来记录API,它也将使用它们来序列化和验证数据。
使用多个模型更新应用程序
现在,让我们稍微重构一下这个应用程序,以提高安全性和多功能性。
如果你查看之前的应用程序,在UI中你可以看到,到目前为止,它让客户端决定要创建的英雄的id。😱
我们不应该让这种情况发生,他们可能会覆盖我们已经在数据库中分配的id。决定id应该由后端或数据库完成,而不是由客户端完成。
此外,我们为英雄创建了一个secret_name,但到目前为止,我们到处都在返回它,这不是什么秘密。。。😅
我们将通过添加一些额外的模型来解决这些问题。SQLModel将在这里大放异彩。✨
源代码:
from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: intclass HeroCreate(HeroBase):secret_name: strclass HeroUpdate(HeroBase):name: str | None = Noneage: int | None = Nonesecret_name: str | None = Nonesqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables():SQLModel.metadata.create_all(engine)def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]
app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):db_hero = Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)return db_hero@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
):heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):hero_db = session.get(Hero, hero_id)if not hero_db:raise HTTPException(status_code=404, detail="Hero not found")hero_data = hero.model_dump(exclude_unset=True)hero_db.sqlmodel_update(hero_data)session.add(hero_db)session.commit()session.refresh(hero_db)return hero_db@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}
创建多个模型
在SQLModel中,任何具有table=True的模型类都是表模型。
任何没有table=True的模型类都是数据模型,这些模型实际上只是Pydantic模型(带有一些小的额外功能)。🤓
使用SQLModel,我们可以使用继承来避免在所有情况下复制所有字段。
HeroBase-基类
让我们从一个HeroBase模型开始,该模型包含所有模型共享的所有字段:
名称
年龄
nameage
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)
英雄-桌子模型
然后,让我们创建Hero,即实际的表模型,其中包含其他模型中并不总是包含的额外字段:
身份证件
秘密名称
idsecret_name
因为Hero继承自HeroBase,所以它也有在HeroBase中声明的字段,所以Hero的所有字段都是:
身份证件
名称
年龄
秘密名称
idnameagesecret_name
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: str
HeroPublic-公共数据模型
接下来,我们创建一个HeroPublic模型,该模型将返回给API的客户端。
它具有与HeroBase相同的字段,因此不包括secret_name。
最后,我们英雄的身份得到了保护!🥷
它还重新声明id:int。通过这样做,我们与API客户端签订了合同,这样他们就可以总是期望id在那里并且是int(永远不会是None)。
小贴士
让返回模型确保一个值总是可用的,并且总是int(而不是None)对API客户端非常有用,他们可以编写更简单的具有这种确定性的代码。
此外,自动生成的客户端将具有更简单的接口,因此与您的API通信的开发人员可以更好地使用您的API。😎
HeroPublic中的所有字段都与HeroBase中的相同,id声明为int(不是None):
身份证件
名称
年龄
秘密名称
idnameagesecret_name
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: int
HeroCreate-创建英雄的数据模型
现在我们创建一个HeroCreate模型,这个模型将验证来自客户端的数据。
它具有与HeroBase相同的字段,还具有secret_name。
现在,当客户端创建一个新英雄时,他们将发送secret_name,它将存储在数据库中,但这些秘密名称不会在API中返回给客户端。
小贴士
这就是你处理密码的方式。接收它们,但不要在API中返回它们。
您还可以在存储密码之前对其值进行哈希运算,切勿以纯文本形式存储。
HeroCreate的字段包括:
名称
年龄
秘密名称
nameagesecret_name
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: intclass HeroCreate(HeroBase):secret_name: str
HeroUpdate-更新英雄的数据模型
在之前的应用程序版本中,我们没有更新英雄的方法,但现在有了多个模型,我们可以做到。🎉
HeroUpdate数据模型有点特殊,它具有创建新英雄所需的所有相同字段,但所有字段都是可选的(它们都有一个默认值)。这样,当你更新英雄时,你可以只发送你想要更新的字段。
因为所有字段实际上都发生了变化(类型现在包括None,它们现在的默认值为None),我们需要重新声明它们。
我们真的不需要从HeroBase继承,因为我们正在重新声明所有字段。为了保持一致性,我会让它继承,但这不是必需的。这更多的是个人品味的问题。🤷
HeroUpdate的字段包括:
名称
年龄
秘密名称
nameagesecret_name
class HeroUpdate(HeroBase):name: str | None = Noneage: int | None = Nonesecret_name: str | None = None
使用HeroCreate创建并返回一个HeroPublic
现在我们有了多个模型,我们可以更新应用程序中使用它们的部分。
我们在请求中接收HeroCreate数据模型,并从中创建Hero表模型。
这个新的表模型Hero将具有客户端发送的字段,并且还将具有数据库生成的id。
然后,我们返回与函数中相同的表模型Hero。但是,当我们使用HeroPublic数据模型声明response_model时,FastAPI将使用HeroPublic来验证和序列化数据。
@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):db_hero = Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)return db_hero
小贴士
现在我们使用response_model=HeroPublic而不是返回类型注释->HeroPublic,因为我们返回的值实际上不是HeroPublic。
如果我们声明了->HeroPublic,你的编辑和linter会抱怨(这是理所当然的)你返回的是Hero而不是HeroPublic。
通过在response_model中声明它,我们告诉FastAPI去做它的事情,而不会干扰类型注释以及编辑器和其他工具的帮助。
用HeroPublic阅读英雄
我们可以像以前一样读取Heros,同样,我们使用response_model=list[HeroPublic]来确保数据被正确验证和序列化。
@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
):heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes
与HeroPublic一起阅读《一个英雄》
我们可以读一个英雄:
@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero
使用HeroUpdate更新英雄
我们可以更新英雄。为此,我们使用HTTP PATCH操作。
在代码中,我们得到一个包含客户端发送的所有数据的字典,只有客户端发送的数据,不包括任何仅作为默认值的值。为此,我们使用exclude_unset=True。这是主要的伎俩。🪄
然后,我们使用hero_db.sqlmodel_update(hero_data)用hero_da中的数据更新hero_db。
@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):hero_db = session.get(Hero, hero_id)if not hero_db:raise HTTPException(status_code=404, detail="Hero not found")hero_data = hero.model_dump(exclude_unset=True)hero_db.sqlmodel_update(hero_data)session.add(hero_db)session.commit()session.refresh(hero_db)return hero_db
再次删除英雄
删除英雄几乎是一样的。
我们不会满足在这个项目中重构所有内容的愿望。😅
@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}
再次运行应用程序
您可以再次运行该应用程序:
fastapi dev main.py
输出信息:Uvicorn正在运行http://127.0.0.1:8000(按CTRL+C退出)
如果你转到/docs API UI,你会看到它现在已经更新,并且它不会期望在创建英雄时从客户端接收id,等等。

回顾
您可以使用SQLModel与SQL数据库交互,并使用数据模型和表模型简化代码。
您可以在SQLModel文档中了解更多信息,其中有一个关于使用SQLModel和FastAPI的较长迷你教程。🚀
实践
安装SQLModel
首先,确保创建虚拟环境,激活它,然后安装sqlmodel:
pip install sqlmodel
源代码
存储文件到sql.py
from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: intclass HeroCreate(HeroBase):secret_name: strclass HeroUpdate(HeroBase):name: str | None = Noneage: int | None = Nonesecret_name: str | None = Nonesqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables():SQLModel.metadata.create_all(engine)def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]
app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):db_hero = Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)return db_hero@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
):heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):hero_db = session.get(Hero, hero_id)if not hero_db:raise HTTPException(status_code=404, detail="Hero not found")hero_data = hero.model_dump(exclude_unset=True)hero_db.sqlmodel_update(hero_data)session.add(hero_db)session.commit()session.refresh(hero_db)return hero_db@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}
启动服务
执行命令:
fastapi dev sql.py
执行后显示:
INFO Importing from /Users/skywalk/work/fastapi ╭─ Python module file ─╮ │ │ │ 🐍 sql.py │ │ │ ╰──────────────────────╯ INFO Importing module sql
INFO Found importable FastAPI app ╭─ Importable FastAPI app ─╮ │ │ │ from sql import app │ │ │ ╰──────────────────────────╯ INFO Using import string sql:app ╭────────── FastAPI CLI - Development mode ───────────╮ │ │ │ Serving at: http://127.0.0.1:8000 │ │ │ │ API docs: http://127.0.0.1:8000/docs │ │ │ │ Running in development mode, for production use: │ │ │ │ fastapi run │ │ │ ╰─────────────────────────────────────────────────────╯ INFO: Will watch for changes in these directories: ['/Users/xxx/work/fastapi']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [37935] using WatchFiles
INFO: Started server process [37941]
INFO: Waiting for application startup.
INFO: Application startup complete.
测试
浏览docs页面:

执行curl添加指令
curl -X 'POST' \'http://127.0.0.1:8000/heroes/' \-H 'accept: application/json' \-H 'Content-Type: application/json' \-d '{"name": "string","age": 0,"secret_name": "string"
}'
输出:
{"name":"string","age":0,"id":2}
证明一条信息被添加
查看一下:
curl http://127.0.0.1:8000/heroes/
[{"name":"string","age":0,"id":1},{"name":"string","age":0,"id":2}]
果然多了一条信息。
相关文章:
三周精通FastAPI:27 使用使用SQLModel操作SQL (关系型) 数据库
官网文档:https://fastapi.tiangolo.com/zh/tutorial/sql-databases/ SQL (关系型) 数据库 FastAPI不需要你使用SQL(关系型)数据库。 但是您可以使用任何您想要的关系型数据库。 这里我们将看到一个使用SQLModel的示例。 SQLModel是在SQLAlchemy和Pydantic的基础…...
Kubernetes金丝雀发布
华子目录 Canary金丝雀发布什么是金丝雀发布Canary发布方式基于header(http包头)灰度发布基于权重的金丝雀发布 Canary金丝雀发布 什么是金丝雀发布 金丝雀发布也称为灰度发布,是一种软件发布策略主要目的是在将新版本的软件全面推广到生产环…...
树形DP讲解
文章目录 树形DP讲解一、引言二、树形DP基础1、树的定义2、树形DP的基本思想3、代码示例:子树大小 三、经典例题解析1、树的平衡点1.1、代码示例 2、没有上司的舞会(树的最大独立集)2.1、代码示例 四、总结 树形DP讲解 一、引言 树形动态规…...
容器:如何调试容器
调试容器,主要是指的调试Dockerfile,调试Dockerfile中的各个命令的执行,大小等 1、docker history查看构建过程和所有的中间层 2、docker run rm -it -u root XXX sh,通过临时容器的方式启动,可以调试中间层文件 3、do…...
用图说明 CPU、MCU、MPU、SoC 的区别
CPU CPU 负责执行构成计算机程序的指令,执行这些指令所指定的算术、逻辑、控制和输入/输出(I/O)操作。 MCU (microcontroller unit) 不同的 MCU 架构如下,注意这里的 MPU 表示 memory protection unit MPU (microprocessor un…...
牛客周赛 Round 65
文章目录 超市思路:Solved: 雨幕思路:Solved: 闺蜜思路:Solved: 医生思路:Solved: 降温(easy)思路:Solved: F-降温(hard&a…...
超级经典的79个软件测试面试题(内含答案)
1、软件的生命周期(prdctrm) 计划阶段(planning)-〉需求分析(requirement)-〉设计阶段(design)-〉编码(coding)->测试(testing)->运行与维护(running maintrnacne) 测试用例 用例编号 测试项目 测试标题 重要级别 预置条件 输入数据 执行步骤 预期结果 2、问…...
【Mac】安装 F5-TTS
1、下载项目 项目地址:【GitHub】 SWivid F5-TTS 2、创建并激活 Python 虚拟环境 # 创建 Python 虚拟环境 userMac F5-TTS-main % python3 -m venv f5-tts# 激活进入 Python 虚拟环境 userMac F5-TTS-main % source f5-tts/bin/activate (f5-tts) userrMac F5-TT…...
Leaflet查询矢量瓦片偏移的问题
1、问题现象 使用Leaflet绘制工具查询出来的结果有偏移 2、问题排查 1)Leaflet中latLngToContainerPoint和latLngToLayerPoint的区别 2)使用Leaflet查询需要使用像素坐标 3)经排查发现,container获取的坐标是地图容器坐标&…...
存储引擎技术进化
B-tree 目前支撑着数据库产业的半壁江山。 50 年来不变而且人们还没有改变它的意向 鉴定一个算法的优劣,有一个学派叫 IO复杂度分析 ,简单推演真假便知。 下面就用此法分析下 B-tree(traditional b-tree) 的 IO 复杂度,对读、写 IO 一目了…...
CentOS 9 Stream 上安装 Maven
CentOS 9 Stream 上安装 Maven 在 CentOS 9 Stream 上安装 Maven,可以按照以下步骤进行: 更新系统软件包: sudo dnf update安装 Maven: CentOS 9 Stream 默认的包管理器中已经包含 Maven,你可以直接安装: s…...
强势改进!TCN-Transformer时间序列预测
强势改进!TCN-Transformer时间序列预测 目录 强势改进!TCN-Transformer时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现TCN-Transformer时间序列预测; 2.运行环境为Matlab2023b; 3.单个变量时间序…...
MyBatis的不同参数传递封装
MyBatis参数传递 传参方式 1. 使用 #{} 占位符 这是 MyBatis 中最常用的参数传递方式。它将参数直接替换到 SQL 语句中的占位符位置。 单个参数: <select id"selectUserById" resultType"User">SELECT * FROM users WHERE id #{id}…...
kotlin 协程方法总结
Kotlin 协程是一套强大的异步编程工具,以下是对 Kotlin 协程常用方法的总结: 1. 协程构建器 launch: 启动一个新的协程,不阻塞当前线程,返回一个 Job 对象。 GlobalScope.launch {// 协程体}async: 启动一个新的协程并返回一个…...
脉冲当量计算方法
脉冲的概念: 脉冲当量是指控制器输出一个定位控制脉冲时,所产生的定位控制移动的位移。在直线运动中,它表示移动的距离;在圆周运动中,它表示转动的角度。简而言之,脉冲当量就是电机接收一个脉冲信号后能够移…...
TongWeb7.0.E.6_P11嵌入式版本使用指引(by lqw)
文章目录 声明相关概念手册的使用示范工程安装工程介质 安装前准备示范工程参考(spring-boot-helloWorld-2.x)示范参考 声明 1.本文参考001_TongWeb_V7.0嵌入式版_JavaEE标准容器用户指南_70E6_P11A01.pdf,实际以最新更新的手册为准。 2.本文…...
Node.js:Express 服务 路由
Node.js:Express 服务 & 路由 创建服务处理请求req对象 静态资源托管托管多个资源挂载路径前缀 路由模块化 Express是Node.js上的一个第三方框架,可以快速开发一个web框架。本质是一个包,可以通过npm直接下载。 创建服务 Express创建一…...
C++之多态(上)
C之多态 多态的概念 多态(polymorphism)的概念:通俗来说,就是多种形态。多态分为编译时多态(静态多态)和运⾏时多 态(动态多态),这⾥我们重点讲运⾏时多态,编译时多态(静态多态)和运⾏时多态(动态多态)。编译时 多态(静态多态)主…...
PySpark单机模式安装教程
目录 1. 环境准备 1.1 安装要求 1.2 检查Python和Java环境 2. 下载并解压Spark 2.1 下载Spark 2.2 解压安装包 3. 配置环境变量 4. 配置Spark 5. 启动Spark Shell 6. 运行测试 7. 关闭Spark Shell 8. 常见问题 8.1 兼容性问题 8.2 环境变量配置 总结 1. 环境准备…...
DEVOPS: 认证与调度
概述 不知道大家有没有意识到一个现实,就是大部分时候,我们已经不像以前一样通过命令行,或者可视窗口来使用一个系统了现在我们上微博、或者网购,操作的其实不是眼前这台设备,而是一个又一个集群 通常,这样…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
