Python dash-fastapi前后端搭建過程
概述
項(xiàng)目中需要快速搭建一個(gè)前后端系統(tǒng),涉及到dash-fastapi架構(gòu)的時(shí)候,對該架構(gòu)的時(shí)候進(jìn)行總結(jié)。本文主要總結(jié)的是對該架構(gòu)的基本使用,后續(xù)再對該架構(gòu)的項(xiàng)目源碼進(jìn)行總結(jié)分析
此處實(shí)現(xiàn)一個(gè)小的demo,迷你任務(wù)管理器,后端使用FastAPI,前端則使用Dash,數(shù)據(jù)存儲(chǔ)暫時(shí)使用列表進(jìn)行存儲(chǔ),主要功能如下
- 任務(wù)列表展示: 前端頁面顯示一個(gè)簡單的任務(wù)列表,包含任務(wù)標(biāo)題和狀態(tài)。
- 添加任務(wù): 用戶可以在前端輸入任務(wù)標(biāo)題,點(diǎn)擊按鈕添加新任務(wù)。
- 刷新任務(wù)列表: 點(diǎn)擊按鈕可以刷新任務(wù)列表,從后端獲取最新數(shù)據(jù)。
整體架構(gòu)理解
代碼主體架構(gòu)
后端
- main.py (Fast API主文件)
- requirements.txt(后端依賴)
前端
- app.py(Dash主文件)
- api_client.py(前端API客戶端)
- layoputs.py(前端布局)
- callbacks.py(前端回調(diào)函數(shù))
- requirements.txt(后端依賴)
主要邏輯理解
代碼中具體體現(xiàn)
后端
- main.py:后端,也就類似于廚房。專門負(fù)責(zé)接收顧客的訂單,然后準(zhǔn)備食物(構(gòu)建響應(yīng))并告知服務(wù)器食物準(zhǔn)備后
- tasks_db = []:通過列表內(nèi)存列表,類似于廚師的菜單列表。其記錄了餐廳可以提供的菜品,也就是后端可以完成的任務(wù)
- @app.get :廚師提供給服務(wù)員今日菜單,服務(wù)員發(fā)送get請求的時(shí)候,就可以知道后端提供什么服務(wù)(從tasks_db中獲?。?/li>
- @app.post:創(chuàng)創(chuàng)建任務(wù),類似于服務(wù)員將菜單傳給廚房;后面的邏輯就是請求響應(yīng)的基本邏輯
- Task(使用Pydantic模型):菜單上的菜品敘述,規(guī)定了每個(gè)任務(wù)包含哪些信息,提供任務(wù)名以及狀態(tài)是否完成
前端
- layouts.py:餐廳的菜單,定義了顧客可以看到什么,也就是前端顯示的頁面
- dcc.Input:點(diǎn)餐單的填寫區(qū)域,顧客要吃什么
- dbc.Button:提交按鈕,這里可以對應(yīng)設(shè)計(jì)供,例如提交點(diǎn)餐單或者是刷新菜單信息
- html.Div:上菜的盤子,廚房準(zhǔn)備后的食物會(huì)放進(jìn)這個(gè)盤子里展示給顧客
- callbacks.py:服務(wù)員接收到顧客的指令應(yīng)該如何行動(dòng)
- api_client.py:點(diǎn)餐系統(tǒng),幫助前端與后端溝通,服務(wù)員與廚師之間的溝通
具體實(shí)現(xiàn)
該實(shí)例主要用于理解該結(jié)構(gòu)的運(yùn)行
代碼
后端:主要提供兩個(gè)方法,獲取所有任務(wù)列表和創(chuàng)建新任務(wù)
# backend/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List app = FastAPI() # 模擬內(nèi)存數(shù)據(jù)庫 (使用 Python 列表) tasks_db = [] # 用于生成唯一的用戶ID task_id_counter = 1 class Task(BaseModel): id: int title: str status: str = "待完成" # 默認(rèn)狀態(tài) class TaskCreate(BaseModel): title: str class TaskResponse(BaseModel): tasks: List[Task] @app.get("/api/tasks", response_model=TaskResponse) async def get_tasks(): """獲取所有任務(wù)列表""" return TaskResponse(tasks=tasks_db) @app.post("/api/tasks", response_model=Task) async def create_task(task_create: TaskCreate): """創(chuàng)建新任務(wù)""" global task_id_counter new_task = Task(id=task_id_counter, title=task_create.title) tasks_db.append(new_task) task_id_counter += 1 return new_task if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)
后端依賴:requirements.txt
fastapi uvicorn pydantic
前端代碼:api_client.py(向服務(wù)端發(fā)起請求)
import requests API_BASE_URL = "http://localhost:8000/api" # 后端 API 基礎(chǔ) URL def get_task_list(): """獲取任務(wù)列表""" url = f"{API_BASE_URL}/tasks" response = requests.get(url) response.raise_for_status() # 檢查請求是否成功 (狀態(tài)碼 2xx) return response.json() def create_new_task(title): """創(chuàng)建新任務(wù)""" url = f"{API_BASE_URL}/tasks" headers = {'Content-Type': 'application/json'} data = {'title': title} response = requests.post(url, headers=headers, json=data) response.raise_for_status() return response.json()
前端回調(diào):callbacks.py,當(dāng)顧客觸碰哪些按鈕后與后端交互然后返回的邏輯實(shí)現(xiàn)
from dash import Output, Input, State from .app import app # 導(dǎo)入 Dash app 實(shí)例 from frontend import api_client # 導(dǎo)入 API 客戶端 import dash_html_components as html import dash @app.callback( Output("task-list-output", "children"), [Input("refresh-tasks-button", "n_clicks"), Input("add-task-button", "n_clicks")], [State("new-task-title", "value")] ) def update_task_list(refresh_clicks, add_clicks, new_task_title): """更新任務(wù)列表顯示""" triggered_id = [p['prop_id'] for p in dash.callback_context.triggered][0] if "add-task-button" in triggered_id: if new_task_title: api_client.create_new_task(new_task_title) # 調(diào)用 API 創(chuàng)建新任務(wù) tasks_data = api_client.get_task_list() # 調(diào)用 API 獲取任務(wù)列表 task_items = [] if tasks_data and tasks_data.get('tasks'): # 檢查 tasks_data 和 tasks 鍵是否存在 for task in tasks_data['tasks']: task_items.append(html.Li(f"{task['title']} - 狀態(tài): {task['status']} (ID: {task['id']})")) else: task_items.append(html.Li("暫無任務(wù)")) return html.Ul(task_items)
前端頁面布局layouts.py
import dash_html_components as html import dash_core_components as dcc import dash_bootstrap_components as dbc layout = dbc.Container([ html.H1("迷你任務(wù)管理器"), dbc.Row([ dbc.Col([ html.Div("任務(wù)標(biāo)題:"), dcc.Input(id="new-task-title", type="text", placeholder="請輸入任務(wù)標(biāo)題"), dbc.Button("添加任務(wù)", id="add-task-button", n_clicks=0, className="mt-2"), ]), ]), html.Hr(className="mt-3"), html.H4("任務(wù)列表"), dbc.Button("刷新任務(wù)列表", id="refresh-tasks-button", n_clicks=0, className="mb-2"), html.Div(id="task-list-output"), # 用于顯示任務(wù)列表 ])
前端依賴
dash dash-bootstrap-components requests
pydantic補(bǔ)充
""" 簡單事例 """ # from pydantic import BaseModel # # class User(BaseModel): # id: int # name: str # email: str # is_active: bool = True # 默認(rèn)值 # # # 示例數(shù)據(jù) # user_data = { # 'id': 1, # 'name': 'Alice', # 'email': 'alice@example.com', # } # # # 使用 Pydantic 模型進(jìn)行數(shù)據(jù)驗(yàn)證和解析 # user = User(**user_data) # print(user) """ 復(fù)雜事例的封裝 """ from pydantic import BaseModel from typing import List class Address(BaseModel): street: str city: str zip_code: str class User(BaseModel): id: int name: str address: Address # 嵌套模型 # 創(chuàng)建嵌套數(shù)據(jù) user_data = { 'id': 1, 'name': 'John', 'address': { 'street': '123 Main St', 'city': 'New York', 'zip_code': '10001', } } user = User(**user_data) print(user)
前端回調(diào)邏輯
@app.callback( Output("task-list-output", "children"), [Input("refresh-tasks-button", "n_clicks"), Input("add-task-button", "n_clicks")], [State("new-task-title", "value")] ) def update_task_list(refresh_clicks, add_clicks, new_task_title): """更新任務(wù)列表顯示""" triggered_id = [p['prop_id'] for p in dash.callback_context.triggered][0] if "add-task-button" in triggered_id: if new_task_title: api_client.create_new_task(new_task_title) # 調(diào)用 API 創(chuàng)建新任務(wù) tasks_data = api_client.get_task_list() # 調(diào)用 API 獲取任務(wù)列表 task_items = [] if tasks_data and tasks_data.get('tasks'): # 檢查 tasks_data 和 tasks 鍵是否存在 for task in tasks_data['tasks']: task_items.append(html.Li(f"{task['title']} - 狀態(tài): {task['status']} (ID: {task['id']})")) else: task_items.append(html.Li("暫無任務(wù)")) return html.Ul(task_items)
回調(diào)函數(shù)callbacks理解
Dash框架中回調(diào)函數(shù)是實(shí)現(xiàn)交互的關(guān)鍵,其一可以連接前端的UI組件交互和侯丹數(shù)據(jù)的處理邏輯(調(diào)用API或者更新圖表操作),從而實(shí)現(xiàn)動(dòng)態(tài)更新前端UI,而不需要更新整個(gè)頁面
Output("task-list-output", "children")
(輸出)
該處定義了回調(diào)函數(shù)的輸出,其指定了當(dāng)回調(diào)函數(shù)執(zhí)行完畢后,哪個(gè)前端組件的哪個(gè)屬性會(huì)被更新
html.Div(id="task-list-output") # <--- 這里定義了 id="task-list-output" 的 Div 組件
這個(gè)回調(diào)函數(shù)執(zhí)行完成后,將會(huì)更新 id
為 "task-list-output"
的 Div
組件的 children
屬性。 換句話說,回調(diào)函數(shù)的返回值將會(huì)被設(shè)置為這個(gè) Div
組件的內(nèi)容,從而更新任務(wù)列表的顯示
換句話說,output就是上菜的盤子,盤子里面的內(nèi)容就是children屬性
[Input("refresh-tasks-button", "n_clicks"), Input("add-task-button", "n_clicks")]
(輸入 - 觸發(fā)器)
指定了當(dāng)前前端組件的哪些屬性發(fā)生變化的時(shí)候,會(huì)觸發(fā)這個(gè)回調(diào)函數(shù)執(zhí)行
dbc.Button("刷新任務(wù)列表", id="refresh-tasks-button", ...) # <--- 這里定義了 id="refresh-tasks-button" 的按鈕
類似于顧客點(diǎn)擊菜價(jià)查詢,服務(wù)員就會(huì)去問一下菜價(jià),當(dāng)顧客點(diǎn)擊提交餐單的時(shí)候,服務(wù)員就會(huì)立馬去廚房下單
[State("new-task-title", "value")]
(狀態(tài))
指定哪些前端組件的哪些屬性的當(dāng)前值需要傳遞給回調(diào)函數(shù),但是State組件屬性的變化不會(huì)觸發(fā)回調(diào)函數(shù)執(zhí)行
可以理解State就是顧客在菜單上書寫的菜名
當(dāng) update_task_list
回調(diào)函數(shù)被觸發(fā)執(zhí)行時(shí) (因?yàn)?"刷新任務(wù)列表" 按鈕或 "添加任務(wù)" 按鈕被點(diǎn)擊了),Dash 框架會(huì)將 id
為 "new-task-title"
的輸入框組件的 value
屬性的 "當(dāng)前值" 作為參數(shù)傳遞給 update_task_list
函數(shù)。 注意,輸入框內(nèi)容的變化 不會(huì) 直接觸發(fā)回調(diào)函數(shù),只有當(dāng) Input
指定的組件屬性變化時(shí)才會(huì)觸發(fā)
到此這篇關(guān)于Python dash-fastapi前后端搭建的文章就介紹到這了,更多相關(guān)Python dash-fastapi搭建內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python使用FastAPI獲取請求頭信息的兩種方法
- python使用fastapi實(shí)現(xiàn)多語言國際化的操作指南
- Flask與FastAPI對比選擇最佳Python?Web框架的超詳細(xì)指南
- Python 框架 FastAPI詳解
- Python使用fastAPI如何實(shí)現(xiàn)一個(gè)流式傳輸接口
- Python使用fastapi快速編寫一個(gè)增刪改查的接口
- Python web框架fastapi中間件的使用及CORS跨域問題
- Python?搭建?FastAPI?項(xiàng)目的詳細(xì)過程
- Python FastAPI 多參數(shù)傳遞的示例詳解
相關(guān)文章
python3實(shí)現(xiàn)語音轉(zhuǎn)文字(語音識別)和文字轉(zhuǎn)語音(語音合成)
這篇文章主要介紹了python3實(shí)現(xiàn)語音轉(zhuǎn)文字(語音識別)和文字轉(zhuǎn)語音(語音合成),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10python實(shí)現(xiàn)的文件同步服務(wù)器實(shí)例
這篇文章主要介紹了python實(shí)現(xiàn)的文件同步服務(wù)器,實(shí)例分析了文件同步服務(wù)器的原理及客戶端、服務(wù)端的實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-06-06解決pycharm下os.system執(zhí)行命令返回有中文亂碼的問題
今天小編就為大家分享一篇解決pycharm下os.system執(zhí)行命令返回有中文亂碼的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07詳解Python中命令行參數(shù)argparse的常用命令
這篇文章主要為大家詳細(xì)介紹了Python中命令行參數(shù)argparse的一些常用命令,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以了解一下2023-01-01Python?matplotlib?seaborn繪圖教程詳解
Seaborn是在matplotlib的基礎(chǔ)上進(jìn)行了更高級的API封裝,從而使得作圖更加容易,在大多數(shù)情況下使用seaborn就能做出很具有吸引力的圖。本文將詳細(xì)講解如何利用Seaborn繪制圖表,需要的可以參考一下2022-03-03用gpu訓(xùn)練好的神經(jīng)網(wǎng)絡(luò),用tensorflow-cpu跑出錯(cuò)的原因及解決方案
這篇文章主要介紹了用gpu訓(xùn)練好的神經(jīng)網(wǎng)絡(luò),用tensorflow-cpu跑出錯(cuò)的原因及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03Python Pandas數(shù)據(jù)分析工具用法實(shí)例
這篇文章主要介紹了Python Pandas數(shù)據(jù)分析工具用法實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11使用matplotlib.pyplot繪制多個(gè)圖片和圖表實(shí)現(xiàn)方式
這篇文章主要介紹了使用matplotlib.pyplot繪制多個(gè)圖片和圖表的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08