撙仿 发表于 2025-6-2 00:25:25

FastAPI中的复杂查询与原子更新指南

title: FastAPI中的复杂查询与原子更新指南
date: 2025/05/02 20:33:32
updated: 2025/05/02 20:33:32
author:cmdragon
excerpt:
FastAPI 结合 Tortoise-ORM 实现复杂查询与原子更新。通过 Q 对象构建多条件查询,支持 AND、OR、NOT 逻辑运算符,动态组合查询条件。使用 F 表达式进行原子更新,避免竞态条件,确保数据一致性。示例包括订单状态与金额的复杂查询、库存扣减的原子操作,以及商品促销的价格更新。常见错误包括字段拼写错误、类型不匹配和空结果集,需通过模型检查和异常处理解决。
categories:

[*]后端开发
[*]FastAPI
tags:

[*]FastAPI
[*]Tortoise-ORM
[*]复杂查询
[*]原子更新
[*]Q对象
[*]F表达式
[*]数据库操作
扫描二维码
关注或者微信搜一搜:编程智域 前端至全栈交流与成长
探索数千个预构建的 AI 应用,开启你的下一个伟大创意:https://tools.cmdragon.cn/
第一章:FastAPI复杂查询与原子更新实战

1. 环境准备与模型定义

在开始前确保已安装必要依赖:
pip install fastapi uvicorn tortoise-orm pydantic创建订单模型示例(models.py):
from tortoise.models import Model
from tortoise import fields


class Product(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    stock = fields.IntField(default=0)
    price = fields.DecimalField(max_digits=10, decimal_places=2)


class Order(Model):
    id = fields.IntField(pk=True)
    status = fields.CharField(max_length=20)# pending/completed/canceled
    total_amount = fields.DecimalField(max_digits=10, decimal_places=2)
    product = fields.ForeignKeyField('models.Product', related_name='orders')
    created_at = fields.DatetimeField(auto_now_add=True)创建对应的Pydantic模型(schemas.py):
from pydantic import BaseModel
from datetime import datetime


class OrderOut(BaseModel):
    id: int
    status: str
    total_amount: float
    product_id: int
    created_at: datetime

    class Config:
      orm_mode = True2. 组合Q对象实现复杂查询

2.1 Q对象基础原理

Q对象是Tortoise-ORM的条件表达式构造器,支持逻辑运算符:

[*]& 表示AND
[*]| 表示OR
[*]~ 表示NOT
示例:查询金额大于100且状态为pending的订单
from tortoise.expressions import Q


async def get_orders():
    return await Order.filter(
      Q(total_amount__gt=100) & Q(status="pending")
    ).all()2.2 多条件动态组合

在路由中实现动态过滤(main.py):
from fastapi import APIRouter, Query
from tortoise.expressions import Q

router = APIRouter()


@router.get("/orders", response_model=list)
async def search_orders(
      min_amount: float = Query(None),
      max_amount: float = Query(None),
      status: str = Query(None)
):
    query = Q()
    if min_amount:
      query &= Q(total_amount__gte=min_amount)
    if max_amount:
      query &= Q(total_amount__lte=max_amount)
    if status:
      query &= Q(status=status)

    return await Order.filter(query).prefetch_related('product')2.3 复杂逻辑示例

查询过去7天内金额超过500的已完成订单,或金额低于100的待处理订单:
from datetime import datetime, timedelta


async def complex_query():
    seven_days_ago = datetime.now() - timedelta(days=7)
    return await Order.filter(
      Q(
            Q(created_at__gte=seven_days_ago) &
            Q(total_amount__gt=500) &
            Q(status='completed')
      ) |
      Q(
            Q(total_amount__lt=100) &
            Q(status='pending')
      )
    ).order_by('-created_at')3. 使用F表达式进行原子更新

3.1 F表达式的作用原理

F表达式直接在数据库层面执行运算,避免竞态条件。示例:安全扣减库存
from tortoise.expressions import F


async def decrease_stock(product_id: int, quantity: int):
    await Product.filter(id=product_id).update(
      stock=F('stock') - quantity
    )3.2 复合更新操作

同时更新多个字段:
async def update_product_price(product_id: int, new_price: float):
    await Product.filter(id=product_id).update(
      price=new_price,
      last_updated=datetime.now(),
      version=F('version') + 1
    )3.3 条件更新示例

只有当库存充足时才允许扣减:
async def safe_purchase(product_id: int, quantity: int):
    updated = await Product.filter(
      id=product_id,
      stock__gte=quantity
    ).update(stock=F('stock') - quantity)

    if not updated:
      raise HTTPException(400, "库存不足")4. 完整案例演示

实现商品促销接口:
@router.post("/products/{product_id}/promotion")
async def create_promotion(
      product_id: int,
      discount: float = Body(..., gt=0, lt=1)
):
    # 原子更新价格并记录操作
    updated = await Product.filter(id=product_id).update(
      price=F('price') * (1 - discount),
      promotion_count=F('promotion_count') + 1
    )

    if not updated:
      raise HTTPException(404, "商品不存在")

    # 获取更新后的对象
    product = await Product.get(id=product_id)
    return {
      "new_price": float(product.price),
      "promotion_count": product.promotion_count
    }5. 常见报错解决方案

错误1:字段不存在

FieldError: Unknown field 'total_amout' for model Order
原因:字段名拼写错误(amout → amount)
解决:检查模型定义和查询字段是否一致
错误2:类型不匹配

ValidationError: 1 validation error for OrderOut...
原因:Decimal字段自动转换为float时精度丢失
解决:在Pydantic模型中使用Decimal类型并配置json_encoders
错误3:空结果集

DoesNotExist: Object does not exist
原因:查询条件过于严格导致无结果
解决:添加异常处理或使用first()代替get()
6. 课后Quiz


[*]当需要同时满足三个条件时,Q对象应该如何组合?
A) Q(a) | Q(b) | Q(c)
B) Q(a) & Q(b) & Q(c)
C) Q(a) & (Q(b) | Q(c))
答案:B。& 运算符用于AND条件组合
[*]为什么要使用F表达式而不是先查询再更新?
A) 减少数据库查询次数
B) 避免并发导致的数据不一致
C) 两种方式效果相同
答案:B。F表达式保证原子操作,防止竞态条件
[*]如何防止通过Q对象构造的查询出现SQL注入?
A) 手动转义参数
B) 使用ORM的内置参数化查询
C) 限制用户输入字段
答案:B。Tortoise-ORM会自动处理查询参数化
余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:FastAPI中的复杂查询与原子更新指南 | cmdragon's Blog
往期文章归档:


[*]深入解析Tortoise-ORM关系型字段与异步查询 | cmdragon's Blog
[*]FastAPI与Tortoise-ORM模型配置及aerich迁移工具 | cmdragon's Blog
[*]异步IO与Tortoise-ORM的数据库 | cmdragon's Blog
[*]FastAPI数据库连接池配置与监控 | cmdragon's Blog
[*]分布式事务在点赞功能中的实现 | cmdragon's Blog
[*]Tortoise-ORM级联查询与预加载性能优化 | cmdragon's Blog
[*]使用Tortoise-ORM和FastAPI构建评论系统 | cmdragon's Blog
[*]分层架构在博客评论功能中的应用与实现 | cmdragon's Blog
[*]深入解析事务基础与原子操作原理 | cmdragon's Blog
[*]掌握Tortoise-ORM高级异步查询技巧 | cmdragon's Blog
[*]FastAPI与Tortoise-ORM实现关系型数据库关联 | cmdragon's Blog
[*]Tortoise-ORM与FastAPI集成:异步模型定义与实践 | cmdragon's Blog
[*]异步编程与Tortoise-ORM框架 | cmdragon's Blog
[*]FastAPI数据库集成与事务管理 | cmdragon's Blog
[*]FastAPI与SQLAlchemy数据库集成 | cmdragon's Blog
[*]FastAPI与SQLAlchemy数据库集成与CRUD操作 | cmdragon's Blog
[*]FastAPI与SQLAlchemy同步数据库集成 | cmdragon's Blog
[*]SQLAlchemy 核心概念与同步引擎配置详解 | cmdragon's Blog
[*]FastAPI依赖注入性能优化策略 | cmdragon's Blog
[*]FastAPI安全认证中的依赖组合 | cmdragon's Blog
[*]FastAPI依赖注入系统及调试技巧 | cmdragon's Blog
[*]FastAPI依赖覆盖与测试环境模拟 | cmdragon's Blog
[*]FastAPI中的依赖注入与数据库事务管理 | cmdragon's Blog
[*]FastAPI依赖注入实践:工厂模式与实例复用的优化策略 | cmdragon's Blog
[*]FastAPI依赖注入:链式调用与多级参数传递 | cmdragon's Blog
[*]FastAPI依赖注入:从基础概念到应用 | cmdragon's Blog
[*]FastAPI中实现动态条件必填字段的实践 | cmdragon's Blog
[*]FastAPI中Pydantic异步分布式唯一性校验 | cmdragon's Blog
[*]掌握FastAPI与Pydantic的跨字段验证技巧 | cmdragon's Blog
[*]FastAPI中的Pydantic密码验证机制与实现 | cmdragon's Blog
[*]深入掌握FastAPI与OpenAPI规范的高级适配技巧 | cmdragon's Blog
[*]Pydantic字段元数据指南:从基础到企业级文档增强 | cmdragon's Blog
[*]Pydantic Schema生成指南:自定义JSON Schema | cmdragon's Blog
[*]Pydantic递归模型深度校验36计:从无限嵌套到亿级数据的优化法则 | cmdragon's Blog
[*]

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: FastAPI中的复杂查询与原子更新指南