Python的 SQLAlchemy动态构建SELECT语句

编程语言 2026-07-09

我现在在尝试写一个接收参数的函数;如果参数不是假值,就把它们放进SELECT语句中一起构建。除非把SELECT语句作为一个对象在同一行里全部写完,否则就无法让它工作。有没有办法动态构建SELECT语句?

def search_land(
    session: Session,
    longitude: float | bool = False,
    latitude: float | bool = False,
    entity: str | bool = False,
    address: str | bool = False,
    county: str | bool = False,
    count: int = 1,
    parcel_id str | bool = False,
    offset: int = 0,
):
    stmt = select(Land).offset(offset).limit(count)
    if longitude is not False:
        stmt.where(Land.longitude.is_(longitude))
    if latitude is not False:
        stmt.where(Land.latitude.is_(latitude))
    if entity is not False:
        stmt.where(Land.address.is_(address))
    if county is not False:
        stmt.where(Land.county.is_(county))
    if parcel_id is not False:
        stmt.where(Land.parcel_id.is_(parcel_id))

    records = session.execute(stmt).all()
    entries = []
    for object in records:
        entries.append((object[0].to_dict()))
    return entries

解决方案

  1. 生成式模式(不可变性)
    https://docs.sqlalchemy.org/en/20/tutorial/data_select.html
    “Select对象是生成性的,意味着每次方法调用都会返回一个新的Select对象,并在其上添加额外的状态。”
    如何应用它:

在构建查询的过程中,重新给变量赋值以保存进度。

#  no
stmt = select(Land)
stmt.where(Land.county == "Orange")
#  yes   
stmt = select(Land)   
stmt = stmt.where(Land.county == "Orange")
  1. 针对ORM对象的.scalars()
    执行session.execute(stmt) 时,SQLAlchemy会返回一个Result对象,里面包含返回的行(类似元组)。
    https://www.google.com/search?q=https://docs.sqlalchemy.org/en/20/tutorial/data_select.html%23selecting-orm-entities-and-columns显示了一个完整的类,你需要的是对象本身,而不是包含对象的一行数据。

  2. 已纠正的动态函数
    将你的函数重写,使之与上述定义保持一致:

from sqlalchemy import select

def search_land(
    session: Session,
    longitude: float | bool = False,
    latitude: float | bool = False,
    entity: str | bool = False,
    address: str | bool = False,
    county: str | bool = False,
    count: int = 1,
    parcel_id: str | bool = False,
    offset: int = 0,
):
    # 1. Initialize the base Select object
    stmt = select(Land)  

    # 2. Dynamically chain and RE-ASSIGN  

    if longitude is not False:  
        stmt = stmt.where(Land.longitude == longitude)  
    if latitude is not False:  
        stmt = stmt.where(Land.latitude == latitude)  
    if entity is not False:  
        stmt = stmt.where(Land.entity == entity)  
    if address is not False:  
        stmt = stmt.where(Land.address == address)  
    if county is not False:  
        stmt = stmt.where(Land.county == county)  
    if parcel_id is not False:  
        stmt = stmt.where(Land.parcel_id == parcel_id)`  

    # 3. Add ordering, limit, and offset  
    stmt = stmt.offset(offset).limit(count)  

    # 4. Execute and use .scalars() to get clean objects  
    records = session.execute(stmt).scalars().all()  

return [obj.to_dict() for obj in records]
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章