sqlmodel -- fastapi 连接关系型数据库

文章目录

技术方案

  1. fastapi 中可以基于sqlmodel连接关系型数据库, 是一种异步ORM方案;
  2. 安装 pip install sqlmodel;
  3. sqlmodel 是基于sqlalchemy、pydantic实现的,所以基于sqlmodel定义的模型类既可以作为sqlalchemy的模型类来操作数据库,实现CRUD,又可以作为pydantic的模型类来实现数据的验证、过滤、序列化、反序列;
  4. 常用的类及方法
    • SQLModel 基类,定义的模型类必须继承该类;
    • Field字段类,用于定义模型类的字段约束;
    • create_engine方法,创建对数据库的连接;
    • Session会话类,实现对数据库的CRUD操作;
    • select 数据查询;
  5. sqlmodel官网教程

单表的CRUD

代码目录结构及数据流导向:

db.py

python 复制代码
# __author__ = "laufing"

# 基于 sqlmodel 异步ORM框架 连接关系数据库
from fastapi import Depends
from typing_extensions import Annotated  # 创建具有元信息的类
from sqlmodel import SQLModel, Field, Session, create_engine, select

# 连接数据库
database_uri = "sqlite:///lauf.db"
engine = create_engine(database_uri, connect_args={"check_same_thread": False})


def get_db():
    with Session(engine) as session:
        yield session


# 创建具有元信息的类
# Session类型,实例来源于get_db
SessionDep = Annotated[Session, Depends(get_db)]

models.py

python 复制代码
# __author__ = "laufing"
# 定义模型类
from typing import Union
from sqlmodel import SQLModel, Field
from pydantic import field_validator


# 单表
class UserModel(SQLModel, table=True):  # 默认的表名usermodel
    # 继承父类,并为其传递参数,将模型类映射为表;
    # 否则仅作为pydantic模型使用
    id: Union[int, None] = Field(default=None, primary_key=True) # nullable
    # 数据库字段的完整性验证
    name: str = Field(..., unique=True, index=True, description="user name", nullable=False)
    email: str = Field(..., index=True, unique=True, nullable=False)

    # 字段验证的自定义逻辑
    @field_validator('email')
    def validate_email(cls, v):
        if "@" not in v:
            raise ValueError("Email address is not valid, no '@'")
        return v

views.py

python 复制代码
from idlelib.query import Query

from fastapi import APIRouter, Query
from .models import UserModel
from .db import get_db, SessionDep
from sqlmodel import select


user_roter = APIRouter(prefix="/users", tags=["users"]) # tags api文档中展示标签


# 查询所有的用户
@user_roter.get("/", status_code=200)
def list_users(session: SessionDep,
               page_num: int = Query(default_factory=lambda:1, ge=1, description="页码"),
               page_size: int = Query(default_factory=lambda: 10, le=100, gt=0, description="每页大小")
               ) -> list[UserModel]:
    # 利用模型类查询所有的用户
    statement = select(UserModel).offset(page_num - 1).limit(page_size)
    users = session.exec(statement).all()

    return users

# 添加一个用户
@user_roter.post("/", status_code=200)
def create_user(session: SessionDep, user: UserModel) -> UserModel:
    # 主动触发自定义字段的验证
    UserModel.model_validate(user)

    # 默认情况下仅验证数据库字段的 完整性约束
    session.add(user)  # 即insert 插入一条
    session.commit()
    session.refresh(user)
    return user

# 查询指定的用户
@user_roter.get("/{uid}", status_code=200)
def get_user(session: SessionDep, uid: int) -> UserModel:
    user = session.get(UserModel, uid)
    return user

# 更新
@user_roter.put("/{uid}", status_code=200)
def update_user(session: SessionDep, uid: int, user: UserModel)-> UserModel:
    user_db = session.get(UserModel, uid)
    data = user.model_dump(exclude_unset=True)  # 排除未给值的字段
    print("data:", data)
    user_db.sqlmodel_update(data)
    # session.add(user)  查询出来的user_db对象已经在会话中,不用再添加(insert)
    session.commit()
    session.refresh(user_db)  # 提交后user_db变量会置空->{}, 必须反刷回来
    return user_db

@user_roter.delete("/{uid}", status_code=200)
def delete_user(session: SessionDep, uid: int):
    user = session.get(UserModel, uid)
    session.delete(user)
    session.commit()
    return {
        "code": 200,
        "msg": "delete user ok"
    }

app.py

python 复制代码
# __author__ = "laufing"
from fastapi import FastAPI, Path
from contextlib import asynccontextmanager
from sqlmodel import SQLModel
from .db import engine


@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动时执行, 创建所有的表
    SQLModel.metadata.create_all(engine)
    yield
    # 启动过后执行


app = FastAPI(lifespan=lifespan)
from .views import user_roter

app.include_router(user_roter)



if __name__ == '__main__':
    # python脚本方式运行服务
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=5050)

    # 开启reload模式
    # uvicorn.run("app.app:app", host="0.0.0.0", port=5050, reload=True, reload_dirs=[".", "../"])

*init*.py

python 复制代码
# __author__ = "laufing"
from .app import app

main.py

python 复制代码
from app import app


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app, host="localhost", port=5050)

执行main.py运行项目,并在浏览器中访问:

即可以实现数据的增删改查。

github仓库的镜像地址参考

相关推荐
科技小花3 小时前
全球化深水区,数据治理成为企业出海 “核心竞争力”
大数据·数据库·人工智能·数据治理·数据中台·全球化
X56614 小时前
如何在 Laravel 中正确保存嵌套动态表单数据(主服务与子服务)
jvm·数据库·python
虹科网络安全5 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
2301_771717215 小时前
解决mysql报错:1406, Data too long for column
android·数据库·mysql
绘梨衣5476 小时前
Docker+FastAPI+MySQL 项目部署报错汇总
mysql·docker·fastapi
小江的记录本6 小时前
【Kafka核心】架构模型:Producer、Broker、Consumer、Consumer Group、Topic、Partition、Replica
java·数据库·分布式·后端·搜索引擎·架构·kafka
dvjr cloi6 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
dFObBIMmai6 小时前
MySQL主从同步中大事务导致的延迟_如何拆分大事务优化同步
jvm·数据库·python
szccyw06 小时前
mysql如何限制特定存储过程执行权限_MySQL存储过程安全访问
jvm·数据库·python
czlczl200209257 小时前
利用“延迟关联”优化 MySQL 巨量数据的深分页查询
数据库·mysql