FastAPI:(11)SQL數據庫

FastAPI:(11)SQL數據庫

由于CSDN無法展示「漸構」的「#d,#e,#t,#c,#v,#a」標簽,推薦訪問我個人網站進行閱讀:Hkini
「漸構展示」如下:在這里插入圖片描述
在這里插入圖片描述

#c 概述 文章內容概括

FastAPI數據庫
SQLModel
數據庫操作
數據模型
表模型
響應模型
會話管理
增刪改查

1.安裝SQLModel

#d SQLModel

SQLModel 是一個用于在 Python 中聲明數據庫模型的庫,它結合了 SQLAlchemy 的 ORM 能力與 Pydantic 的數據驗證特性。它旨在提供一種簡單、統一的方式來定義數據庫表結構,同時用于數據序列化、驗證和交互,主要用于與 FastAPI 等現代 Web 框架集成。
安裝SQLModel通過pip install sqlmodel

重要特征:

  • 雙重用途(ORM + 數據驗證):同時兼容 SQLAlchemy 的 ORM 和 Pydantic 的數據校驗與序列化。
  • 基于類型注解:使用 Python 的類型提示定義字段和數據結構,更直觀地說明數據模型。
  • 自動生成表結構:可通過模型類定義自動生成數據庫表。
  • 對異步和同步均友好:兼容異步和同步數據庫操作,適應不同項目架構。
  • 簡化模型繼承與組合:可繼承基礎類構建只讀模型、創建數據模型、更新模型等多種用途。

#e 電子病歷模型(正例) SQLModel

例子描述
醫院系統中的電子病歷模型 MedicalRecord,可表示為數據庫表,也可用于接收醫生上傳記錄或給前端返回。字段如 patient_id: int, diagnosis: str, record_time: datetime,模型用于數據庫操作和前后端數據傳輸,完全符合 SQLModel 的理念。

特征對比

  • ? 雙重用途:模型同時作為數據庫表結構與 API 的請求/響應模型。
  • ? 基于類型注解:所有字段通過類型注解標明類型。
  • ? 表結構生成:可通過該模型自動創建數據表。
  • ? 異步友好:可用于 FastAPI 異步接口處理。
from sqlmodel import Field, SQLModel, create_engine, Session
from fastapi import FastAPI
from typing import Optional
from datetime import datetimeclass MedicalRecord(SQLModel, table=True):id: Optional[int] = Field(default=None, primary_key=True)patient_id: intdiagnosis: strrecord_time: datetimesqlite_url = "sqlite:///./test.db"
engine = create_engine(sqlite_url, echo=True)
SQLModel.metadata.create_all(engine)app = FastAPI()@app.post("/records/")
def create_record(record: MedicalRecord):with Session(engine) as session:session.add(record)session.commit()session.refresh(record)return record

#e 商品庫存模型(正例) SQLModel

例子描述
電商平臺中的 InventoryItem 模型記錄商品 ID、庫存數量、價格等信息。該模型用于庫存管理模塊的數據表定義,且用于與 API 交互中的庫存變更和查詢,統一使用。

特征對比

  • ? 雙重用途:模型用于數據庫記錄和接口的數據通信。
  • ? 基于類型注解:如 quantity: int, price: float
  • ? 自動生成表結構:可以直接映射為 inventory_items 表。
  • ? 簡化模型繼承:可以輕松派生創建更新庫存的模型。
from sqlmodel import SQLModel, Field, create_engine, Session
from fastapi import FastAPI
from typing import Optionalclass InventoryItem(SQLModel, table=True):id: Optional[int] = Field(default=None, primary_key=True)name: strquantity: intprice: floatengine = create_engine("sqlite:///./inventory.db", echo=True)
SQLModel.metadata.create_all(engine)app = FastAPI()@app.post("/items/")
def add_item(item: InventoryItem):with Session(engine) as session:session.add(item)session.commit()session.refresh(item)return item

#e 外部API響應模型(反例) SQLModel

例子描述
一個天氣服務中,用于解析外部 API 返回數據的 WeatherResponse 模型,字段如 temperature: float, humidity: float, location: str。該模型只用于臨時解析 JSON 響應數據,不涉及數據庫存儲,也不參與任何數據寫入操作。

特征對比

  • ? 雙重用途缺失:僅用于解析數據,不能表示數據庫表。
  • ? 缺乏 ORM 功能:字段雖有類型注解,但無數據庫元數據。
  • ? 無表結構生成意義:該數據模型不參與數據庫操作。
  • ? Pydantic 使用合理:僅作為數據驗證使用,適合用 Pydantic 而非 SQLModel。
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optionalapp = FastAPI()# 外部天氣服務返回的數據格式
class WeatherResponse(BaseModel):location: strtemperature: floathumidity: floatdescription: Optional[str]# 模擬調用外部 API,返回數據結構
@app.get("/weather/", response_model=WeatherResponse)
def get_weather():# 模擬外部 API 響應fake_api_data = {"location": "Chengdu","temperature": 28.5,"humidity": 70.2,"description": "Cloudy"}return fake_api_data

2.單一模型

#e 官網例子(正例) SQLModel

具體步驟:

  1. 創建模型
  2. 創建引擎
  3. 創建表
  4. 創建會話(Session)依賴項:Session 會存儲內存中的對象并跟蹤數據中所需更改的內容,然后它使用 engine 與數據庫進行通信。使用 yield 創建一個 FastAPI 依賴項,為每個請求提供一個新的 Session 。這確保每個請求使用一個單獨的會話。
  5. 啟動創建表:對于生產環境,可能會用一個能夠在啟動應用程序之前運行的遷移腳本如Alembic
  6. 創建Hero類:因為每個 SQLModel 模型同時也是一個 Pydantic 模型,所以可以在與 Pydantic 模型相同的類型注釋中使用它。
  7. 讀取Hero類
  8. 讀取單個Hero
  9. 刪除單個Hero
from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass Hero(SQLModel, table=True): # 利用SQLModel創建數據庫模型,table=True,告訴SQLModel這是一個表模型id: int | None = Field(default=None, primary_key=True) # primary_key表示是主鍵;int | None 數據在SQL應該的是INTEGER并且NULLABLE name: str = Field(index=True) # index=True 創建SQL索引,str在數據庫中將會是TEXT或者VARCHARTage: 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} # 不同線程中使用同一個SQLite數據庫,將會按照代碼結構確保「每個請求使用一個單獨的SQLModel會話」
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables(): # 創建表SQLModel.metadata.create_all(engine)def get_session(): # 創建Session會話依賴項with Session(engine) as session:yield session # 為每個請求提供一個新的SessionSessionDep = Annotated[Session, Depends(get_session)]app = FastAPI()@app.on_event("startup") # 啟動時床啊金數據庫表
def on_startup():create_db_and_tables()@app.post("/heroes/") # 創建Hero類,聲明一個Hero參數,將從json主體中讀取數據,同樣可以聲明為「返回類型」,自動生成API文檔界面
def create_hero(hero: Hero, session: SessionDep) -> Hero:session.add(hero)session.commit()session.refresh(hero)return hero@app.get("/heroes/") # 讀取「Hero」類,并利用limit和offset對結果進行分頁
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}") # 讀取單個「Hero」
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}") # 刪除單個「Hero」
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}

3.多個模型

#c 說明 多個模型

現在稍微重構一下這個應用,以提高安全性多功能性

如果查看之前的應用程序,可以在 UI 界面中看到,到目前為止,由客戶端決定要創建的 Heroid 值。

不應該允許這樣做,因為可能會覆蓋在數據庫中已經分配的 id 。決定 id 的行為應該由后端數據庫來完成,而非客戶端

此外,為 hero 創建了一個 secret_name ,但到目前為止,在各處都返回了它,這就不太秘密了……😅

通過添加一些額外的模型來解決這些問題,而 SQLModel 將在這里大放異彩。

#e 官網多模型例子(正例) SQLModel

操作步驟:

  1. 創建HeroBase基類
  2. 創建Hero表模型
  3. 創建HeroPublic公共數據模型
  4. 創建Hero的數據創建模型HeroCreate
  5. 創建Hero的更新模型HeroUpdateHeroUpdate 數據模型有些特殊,它包含創建新 hero 所需的所有相同字段,但所有字段都是可選的(都有默認值)。這樣,當更新一個 hero 時,可以只發送您想要更新的字段。因為所有字段實際上都發生了變化(類型現在包括 None ,并且現在有一個默認值 None ),需要重新聲明它們,重新聲明所有字段,因此并不是真的需要從 HeroBase 繼承。讓它繼承只是為了保持一致,但這并不必要。這更多是個人喜好的問題。
  6. 使用HeroCreate創建并返回HeroPublic:在請求中接收到一個 HeroCreate 數據模型,然后從中創建一個 Hero 表模型。這個新的表模型 Hero 會包含客戶端發送的字段,以及一個由數據庫生成的 id 。然后將與函數中相同的表模型 Hero 原樣返回。但是由于使用 HeroPublic 數據模型聲明了 response_modelFastAPI 會使用 HeroPublic 來驗證和序列化數據。
  7. HeroPublic讀取Hero
  8. HeroPublic讀取單個Hero
  9. HeroPublic更新單個Hero
from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass HeroBase(SQLModel): # 創建HeroBase基類,「共享字段」name,agename: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True): # 創建Hero表模型,繼承HeroBase的共享字段id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase): # 創建返回給API客戶端的HeroPublic模型,不包括secret_name,保護Heroid: int # 重新聲明 `id: int` 。這樣便與 API 客戶端建立了一種約定,始終可以期待 `id` 存在并且是一個整數 `int`(永遠不會是 `None` )class HeroCreate(HeroBase): # 創建用于創建hero的數據模型secret_name: str #不僅擁有與 `HeroBase` 相同的字段,還有 `secret_name` 。當客戶端創建一個新的hero時,會送 `secret_name` ,被存儲到數據庫中,但這些 `secret_name` 不會通過 API 返回給客戶端class HeroUpdate(HeroBase): # 創建用于更新Hero的數據模型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) # 使用HeroCreate創建,并返回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 # 將與函數中相同的表模型 `Hero` 原樣返回。但是由于使用 `HeroPublic` 數據模型聲明了 `response_model` ,**FastAPI** 會使用 `HeroPublic` 來驗證和序列化數據。@app.get("/heroes/", response_model=list[HeroPublic]) # 用HeroPublic讀取Hero表,使用 `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) #用HeroPublic讀取單個Hero
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) #用`HeroUpdate` 更新單個 Hero
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) #在代碼中,會得到一個 `dict` ,其中包含客戶端發送的所有數據,只有客戶端發送的數據,并排除了任何一個僅僅作為默認值存在的值。為此,用 `exclude_unset=True` 。這是最主要的技巧。hero_db.sqlmodel_update(hero_data) # 利用 `hero_data` 的數據更新 `hero_db`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}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83862.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83862.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83862.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

“智眸·家聯“項目開發(一)

嵌入式開發調試知識點總結(含操作流程) 我們今天解決問題的過程,就像是偵探破案,從最表面的線索(網絡不通)開始,一步步深入,最終找到了案件的核心(硬件不匹配&#xff0…

展開說說Android之Retrofit詳解_使用篇

Retrofit是由Square公司開發的類型安全HTTP客戶端框架,借助動態代理在運行時生成接口實現類,將注解轉化為OkHttp請求配置;節省成本通過轉換器(Gson/Moshi)自動序列化JSON/XML,內部處理網絡請求在主線程返回報文。Retrofit 直譯是封…

復古美學淺綠色文藝風格Lr調色教程,手機濾鏡PS+Lightroom預設下載!

調色介紹 復古美學淺綠色文藝風格 Lr 調色,是基于 Adobe Lightroom(Lr)軟件,為攝影作品賦予特定藝術氛圍的調色方式。通過合理設置軟件中的各項參數與工具,把照片調整為以淺綠色為主調,融合復古元素與文藝氣…

力扣網C語言編程題:缺失的第一個正數第三種解題方法

一. 簡介 前面文章學習了對該題目的兩種解題思路,文章如下: 力扣網C語言編程題:缺失的第一個正數-CSDN博客 但是前面的實現上在空間復雜度上沒有滿足要求。本文學習一種在空間復雜度上為 O(1)的思路。 二. 力扣網C語言編程題:缺…

PyTorch 實現 MNIST 手寫數字識別

PyTorch 實現 MNIST 手寫數字識別 MNIST 是一個經典的手寫數字數據集,包含 60000 張訓練圖像和 10000 張測試圖像。使用 PyTorch 實現 MNIST 分類通常包括數據加載、模型構建、訓練和評估幾個部分。 數據加載與預處理 使用 torchvision 加載 MNIST 數據集&#x…

Python內存互斥與共享深度探索:從GIL到分布式內存的實戰之旅

引言:并發編程的內存困局 在開發高性能Python應用時,我遭遇了這樣的困境:多進程間需要共享百萬級數據,而多線程間又需保證數據一致性。傳統解決方案要么性能低下,要么引發競態條件。本文將深入探討Python內存互斥與共…

【Unity】使用 C# SerialPort 進行串口通信

索引 一、SerialPort串口通信二、使用SerialPort1.創建SerialPort對象,進行基本配置2.寫入串口數據①.寫入串口數據的方法②.封裝數據 3.讀取串口數據①.讀取串口數據的方法②.解析數據 4.讀取串口數據的時機①.DataReceived事件②.多線程接收數據 5.粘包問題處理 一…

如何寫好單元測試:Mock 脫離數據庫,告別 @SpringBootTest 的重型啟動

如何寫好單元測試:Mock 脫離數據庫,告別 SpringBootTest 的重型啟動 作者:Killian(重慶) — 歡迎各位架構獵頭、技術布道者聯系我,項目實戰豐富,代碼穩健,Mock測試愛好者。 技術棧&a…

【DNS】在 Windows 下修改 `hosts` 文件

在 Windows 下修改 hosts 文件,一般用于本地 DNS 覆蓋。操作步驟如下(以 Windows 10/11 為例): 1. 以管理員權限打開記事本 點擊 開始 → 輸入 “記事本”在“記事本”圖標上右鍵 → 選擇 以管理員身份運行 如果提示“是否允許此…

共享內存實現進程通信

目錄 system V共享內存 共享內存示意圖 共享內存函數 shmget函數 shmat函數 shmdt函數 shmctl函數 代碼示例 shm頭文件 構造函數 獲取key值 創建者的構造方式 GetShmHelper 函數 GetShmUseCreate 函數 使用者的構造方式 GetShmForUse 函數 分離附加操作 DetachShm 函數 AttachS…

6月15日星期日早報簡報微語報早讀

6月15日星期日,農歷五月二十,早報#微語早讀。 1、證監會擬修訂期貨公司分類評價:明確扣分標準,優化加分標準; 2、國家考古遺址公園再添10家,全國已評定65家; 3、北京多所高校禁用羅馬仕充電寶…

破解關鍵領域軟件測試“三重難題”:安全、復雜性、保密性

在國家關鍵領域,軟件系統正成為核心戰斗力的一部分。相比通用軟件,關鍵領域軟件在 安全性、復雜性、實時性、保密性 等方面要求極高。如何保障安全合規前提下提升測試效率,確保系統穩定,已成為軟件質量保障的核心挑戰。 關鍵領域…

記錄一次 Oracle DG 異常停庫問題解決過程

記錄一次 Oracle DG 異常停庫問題解決過程 某醫院有以下架構的雙節點 Oracle 集群: 節點1:172.16.20.2 節點2:172.16.20.3 SCAN IP:172.16.20.1 DG:172.16.20.1206月12日,醫院信息科用戶反映無法連接 DG 服務器。 登錄 DG 服務…

MySQL使用EXPLAIN命令查看SQL的執行計劃

1?、EXPLAIN 的語法 MySQL 中的 EXPLAIN 命令是用于分析 SQL 查詢執行計劃的關鍵工具,它能幫助開發者理解查詢的執行方式并找出性能瓶頸??。 語法格式: EXPLAIN <sql語句> 【示例】查詢學生表關聯班級表的執行計劃。 (1)創建班級信息表和學生信息表,并創建索…

Go語言2個協程交替打印

WaitGroup 無緩沖channel waitgroup 用來控制2個協程 Add() 、Done()、Wait() channel用來實現信號的傳遞和信號的打印 ch1: 用來記錄打印的信號 ch2:用來實現信號的傳遞&#xff0c;實現2個協程的順序打印 package mainimport ("fmt""sync" )func ma…

微信小程序 路由跳轉

路由方式 官方參考文檔 wx.switchTab 實現底部導航欄 1.配置信息 app.json"tabBar": {"custom": true,"list": [{"pagePath": "pages/home/index","text": "首頁"},{"pagePath": "p…

[Java 基礎]正則表達式

正則表達式是一種強大的文本模式匹配工具&#xff0c;它使用一種特殊的語法來描述要搜索或操作的字符串模式。在 Java 中&#xff0c;我們可以使用 java.util.regex包提供的類來處理正則表達式。 :::color3 正則表達式不止 Java 語言提供了相應的功能&#xff0c;很多其他語言…

ArcGIS安裝出現1606錯誤解決辦法

問題背景&#xff1a; 由于最近Arcgis10.2打是有些功能不正常退出&#xff0c;比如arctoolbox中的&#xff0c;table to excel 功能&#xff0c;只要一點擊&#xff0c;arcgis就報錯退出&#xff0c;平常在使用過程中&#xff0c;也經常出現一些莫名其妙的崩潰現象&#xff0c…

wpf 解決DataGridTemplateColumn中width綁定失效問題

感謝酪酪烤奶 提供的Solution 文章目錄 感謝酪酪烤奶 提供的Solution使用示例示例代碼分析各類交互流程 WPF DataGrid 列寬綁定機制分析整體架構數據流分析1. ViewModel到Slider的綁定2. ViewModel到DataGrid列的綁定a. 綁定代理(BindingProxy)b. 列寬綁定c. 數據流 關鍵機制詳…

語音轉文本ASR、文本轉語音TTS

ASR Automatic Speech Recognition&#xff0c;語音轉文本。 技術難點&#xff1a; 聲學多樣性 口音、方言、語速、背景噪聲會影響識別準確性&#xff1b;多人對話場景&#xff08;如會議錄音&#xff09;需要區分說話人并分離語音。 語言模型適配 專業術語或網絡新詞需要動…