Python的 SQLAlchemy动态构建SELECT语句
我现在在尝试写一个接收参数的函数;如果参数不是假值,就把它们放进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
解决方案
- 生成式模式(不可变性)
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")
-
针对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显示了一个完整的类,你需要的是对象本身,而不是包含对象的一行数据。 -
已纠正的动态函数
将你的函数重写,使之与上述定义保持一致:
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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。