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

如何将原生SQL转为异步SQLAlchemy并实现动态条件查询

异步SQLAlchemy实现方案

实现完全覆盖两个核心需求:

  • 原生SQL逻辑1:1映射为异步SQLAlchemy 2.0语法
  • search_title参数动态判空,参数为None时自动跳过标题模糊过滤,返回全量统计结果

注意:原SQL中写的FULL JOIN shops存在明显笔误,关联条件为manager.id=cars.manager_id且SELECT子句统计的是cars表数据,以下实现按关联cars表编写,若确实需要关联shops表替换对应模型即可。

前置ORM模型定义

from sqlalchemy import Column, String, DateTime, Integer, ForeignKey, func, case
from sqlalchemy.orm import DeclarativeBase
from datetime import datetime

class Base(DeclarativeBase):
    pass

class Manager(Base):
    __tablename__ = "manager"
    id = Column(Integer, primary_key=True)
    title = Column(String)
    status = Column(String)
    created_at = Column(DateTime, default=datetime.utcnow)

class Cars(Base):
    __tablename__ = "cars"
    id = Column(Integer, primary_key=True)
    manager_id = Column(Integer, ForeignKey("manager.id"))
    status = Column(String)

核心查询实现

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

async def get_manager_car_stats(
    db: AsyncSession,
    search_title: str | None,
    order_key: str,
    page_limit: int
):
    # 排序字段白名单校验,彻底避免SQL注入
    allowed_order_fields = {"title", "status", "created_at"}
    if order_key not in allowed_order_fields:
        raise ValueError("非法排序字段")

    # 构建基础查询框架
    query = (
        select(
            Manager.title,
            Manager.status,
            func.count(Cars.id).label("total_cars"),
            func.count(
                case((Cars.status == "active", 1), else_=None)
            ).label("active_cars"),
            Manager.created_at
        )
        .join(Cars, Manager.id == Cars.manager_id, full=True) # 对应FULL JOIN逻辑
        .group_by(Manager.created_at, Manager.status, Manager.title)
        .order_by(getattr(Manager, order_key))
        .limit(page_limit)
    )

    # 动态追加过滤条件:仅当search_title非None时生效
    if search_title is not None:
        query = query.where(Manager.title.ilike(f"%{search_title}%"))

    # 异步执行查询返回结果
    result = await db.execute(query)
    return result.all()

关键逻辑说明

  • 动态过滤逻辑:先搭建基础查询结构,再判断search_title是否有值,无值时不追加任何标题过滤条件,直接返回全量分组统计结果
  • 聚合逻辑对齐:COUNT(CASE WHEN cars.status='active' THEN 1 END)通过SQLAlchemy内置case构造实现,统计结果和原生SQL完全一致
  • 安全加固:原f-string直接拼接SQL的写法存在注入风险,实现中查询参数由SQLAlchemy自动转义,排序字段提前做白名单校验,彻底规避注入问题
  • 连接类型可调整:join方法的full=True参数对应原生FULL JOIN,可根据业务需要调整参数切换为内连接、左连接
  • 返回结果为命名元组格式,可直接通过.title、.total_cars、.active_cars等属性访问字段值

内容的提问来源于stack exchange,提问作者Akyl Alamanov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:27:18