You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI与Pydantic项目中如何Mock数据库?

如何为FastAPI+Pydantic项目实现Mock数据库?

我正在参与一个基于FastAPI和Pydantic的项目,任务来自GitHub招聘评估仓库,要求如下:

我们希望你以任何合适的方式模拟数据库交互层,并生成用于测试的数据(可以是随机数据)。该数据库层的实现由你决定。

这是我首次使用FastAPI,且从未接触过Mock技术。我已编写了如下代码:

from fastapi import FastAPI, Path
from typing import Optional
from pydantic import BaseModel, Field
import datetime as dt

class TradeDetails(BaseModel):
    buySellIndicator: str = Field(description="A value of BUY for buys, SELL for sells.")

    price: float = Field(description="The price of the Trade.")

    quantity: int = Field(description="The amount of units traded.")


class Trade(BaseModel):
    asset_class: Optional[str] = Field(alias="assetClass", default=None, description="The asset class of the instrument traded. E.g. Bond, Equity, FX...etc")

    counterparty: Optional[str] = Field(default=None, description="The counterparty the trade was executed with. May not always be available")

    instrument_id: str = Field(alias="instrumentId", description="The ISIN/ID of the instrument traded. E.g. TSLA, AAPL, AMZN...etc")

    instrument_name: str = Field(alias="instrumentName", description="The name of the instrument traded.")

    trade_date_time: dt.datetime = Field(alias="tradeDateTime", description="The date-time the Trade was executed")

    trade_details: TradeDetails = Field(alias="tradeDetails", description="The details of the trade, i.e. price, quantity")

    trade_id: str = Field(alias="tradeId", default=None, description="The unique ID of the trade")

    trader: str = Field(description="The name of the Trader")
     
app = FastAPI()

# data = {
#     'asset_class': 'Bond',
#     'conterparty': 'delio',
#     'instrument_id': 'AAPL',
#     'instrument_name': 'Guitar',
#     'trade_date_time':'2023-06-6 12:22',
#     'trade_details':{'buySellIndicator':'BUY', 'price':100.0, 'quantity': 10},
#     'trade_id': '11',
#     'trader':'john'
# }

trade = Trade(assetClass='asset',
    counterparty='count',
    instrumentId='AAPL',
    instrumentName='Guitar',
    tradeDateTime='2023-06-6 12:22',
    tradeDetails={'buySellIndicator':'BUY', 'price':100.0, 'quantity': 10},
    tradeId='11',
    trader='john')

@app.get("/")
def index():
    return {"name": "API Developer Assessment"}

@app.get("/get-trade/{tradeId}")
def get_trade(tradeId:int=Path(description="The Id of the trade you want to view")):
    return trade.tradeId

@app.get("/Trade")
def get_trade_list():
    return trade.dict()

# @app.get('/get-by-query')
# def get_trade()

实现Mock数据库的实用方案

因为是测试场景,不需要真实数据库,用内存结构+随机数据生成就能快速搞定,完全符合需求。

1. 用内存字典模拟数据库表

直接用Python字典存储交易数据,键为trade_id,值为Trade对象,查询、新增操作都很高效:

# 全局变量,模拟数据库的交易表
mock_trade_db = {}

2. 生成随机测试数据

用faker库快速生成真实感的随机数据,先安装依赖:

pip install faker

然后写一个生成随机Trade的函数:

from faker import Faker
import random
from datetime import datetime

fake = Faker()

def generate_random_trade(trade_id: str = None) -> Trade:
    # 定义可选的字段值范围
    asset_classes = ["Bond", "Equity", "FX", "Commodity", None]
    buy_sell_options = ["BUY", "SELL"]
    
    return Trade(
        assetClass=random.choice(asset_classes),
        # 20%概率不提供交易对手
        counterparty=fake.company() if random.random() > 0.2 else None,
        instrumentId=fake.lexify(text="????"),  # 生成4位随机代码
        instrumentName=fake.catch_phrase(),
        tradeDateTime=fake.date_time_this_year(),
        tradeDetails={
            "buySellIndicator": random.choice(buy_sell_options),
            "price": round(random.uniform(10.0, 1000.0), 2),
            "quantity": random.randint(1, 100)
        },
        tradeId=trade_id or fake.uuid4(),  # 自动生成唯一ID如果没提供
        trader=fake.name()
    )

3. 初始化Mock数据库

启动API时预生成几条测试数据,避免空库:

# 启动时生成5条随机交易数据
for i in range(5):
    random_trade = generate_random_trade(f"trade_{i+1}")
    mock_trade_db[random_trade.trade_id] = random_trade

4. 修改接口适配Mock数据库

把原来的接口改成从mock_trade_db读取/写入数据,同时处理不存在的情况:

@app.get("/get-trade/{tradeId}")
def get_trade(tradeId: str = Path(description="The Id of the trade you want to view")):
    # 从Mock数据库查询交易
    target_trade = mock_trade_db.get(tradeId)
    if not target_trade:
        return {"error": "Trade not found"}
    # 用别名返回数据,符合API字段命名规范
    return target_trade.dict(by_alias=True)

@app.get("/Trade")
def get_trade_list():
    # 返回所有交易数据
    return [trade.dict(by_alias=True) for trade in mock_trade_db.values()]

# 可选:新增创建交易的接口,完善CRUD功能
@app.post("/Trade")
def create_trade(trade: Trade):
    # 如果没有提供trade_id,自动生成
    if not trade.trade_id:
        trade.trade_id = fake.uuid4()
    mock_trade_db[trade.trade_id] = trade
    return {"message": "Trade created successfully", "trade_id": trade.trade_id}

5. 进阶:用类封装Mock数据库(可选)

如果想让结构更清晰,模拟真实数据库的CRUD方法,可以封装成类:

class MockTradeDB:
    def __init__(self):
        self._db = {}
    
    def get_by_id(self, trade_id: str) -> Optional[Trade]:
        return self._db.get(trade_id)
    
    def get_all(self) -> list[Trade]:
        return list(self._db.values())
    
    def add(self, trade: Trade):
        self._db[trade.trade_id] = trade
    
    def delete(self, trade_id: str) -> bool:
        if trade_id in self._db:
            del self._db[trade_id]
            return True
        return False

# 实例化Mock数据库
mock_db = MockTradeDB()

# 预生成测试数据
for i in range(5):
    mock_db.add(generate_random_trade(f"trade_{i+1}"))

# 接口中使用封装后的Mock数据库
@app.get("/get-trade/{tradeId}")
def get_trade(tradeId: str = Path(description="The Id of the trade you want to view")):
    trade = mock_db.get_by_id(tradeId)
    if not trade:
        return {"error": "Trade not found"}
    return trade.dict(by_alias=True)

内容的提问来源于stack exchange,提问作者Karthik Bhandary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:40:29