首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在SQLAlchemy中使用"or_“或"and_”构造稍微复杂一点的过滤器

如何在SQLAlchemy中使用"or_“或"and_”构造稍微复杂一点的过滤器
EN

Stack Overflow用户
提问于 2010-04-21 05:02:15
回答 4查看 22.1K关注 0票数 28

我正在尝试从一个术语列表中进行一个非常简单的搜索

代码语言:javascript
运行
复制
terms = ['term1', 'term2', 'term3']

如何以编程方式遍历术语列表并从术语列表构造条件,以便可以使用filteror__and进行查询

代码语言:javascript
运行
复制
query.filter(or_(#something constructed from terms))
EN

回答 4

Stack Overflow用户

发布于 2010-04-21 18:21:47

如果您有一个术语列表,并且希望查找字段与其中之一匹配的行,则可以使用in_()方法:

代码语言:javascript
运行
复制
terms = ['term1', 'term2', 'term3']
query.filter(Cls.field.in_(terms))

如果你想做一些更复杂的事情,那么or_()and_()ClauseElement对象作为参数。SQL及其子类基本上表示查询的ClauseElement AST。通常,通过对Column或InstrumentedAttribute对象调用比较运算符来创建子句元素:

代码语言:javascript
运行
复制
# Create the clause element
clause = (users_table.columns['name'] == "something")
#    you can also use the shorthand users_table.c.name

# The clause is a binary expression ...
print(type(clause))
#    <class 'sqlalchemy.sql.expression._BinaryExpression'>
# ... that compares a column for equality with a bound value.
print(type(clause.left), clause.operator, type(clause.right))
#    <class 'sqlalchemy.schema.Column'>, <built-in function eq>,
#    <class 'sqlalchemy.sql.expression._BindParamClause'>

# str() compiles it to SQL
print(str(clause)) 
# users.name = ?

# You can also do that with ORM attributes
clause = (User.name == "something")
print(str(clause))
# users.name = ?

您可以像处理任何Python对象一样处理表示条件的子句元素,将它们放入列表中,将它们组合到其他子句元素中,等等。因此,您可以这样做:

代码语言:javascript
运行
复制
# Collect the separate conditions to a list
conditions = []
for term in terms:
    conditions.append(User.name == term)

# Combine them with or to a BooleanClauseList
condition = or_(*conditions)

# Can now use the clause element as a predicate in queries
query = query.filter(condition)
# or to view the SQL fragment
print(str(condition))
#    users.name = ? OR users.name = ? OR users.name = ?
票数 31
EN

Stack Overflow用户

发布于 2010-04-21 06:25:03

假设您的terms变量包含有效的SQL语句片段,您可以简单地将前面带有星号的terms传递给or_and_

代码语言:javascript
运行
复制
>>> from sqlalchemy.sql import and_, or_
>>> terms = ["name='spam'", "email='spam@eggs.com'"]
>>> print or_(*terms)
name='spam' OR email='spam@eggs.com'
>>> print and_(*terms)
name='spam' AND email='spam@eggs.com'

请注意,这假设terms只包含有效且正确转义的SQL片段,因此如果恶意用户能够以某种方式访问terms,这可能是不安全的。

与其自己构建SQL片段,不如让SQLAlchemy使用sqlalchemy.sql中的其他方法构建参数化的SQL查询。我不知道您是否为表准备了Table对象;如果是,假设您有一个名为users的变量,它是Table的一个实例,它描述数据库中的users表。然后,您可以执行以下操作:

代码语言:javascript
运行
复制
from sqlalchemy.sql import select, or_, and_
terms = [users.c.name == 'spam', users.c.email == 'spam@eggs.com']
query = select([users], and_(*terms))
for row in conn.execute(query):
    # do whatever you want here

在这里,users.c.name == 'spam'将创建一个sqlalchemy.sql.expression._BinaryExpression对象,该对象记录users表的name列和包含spam的字符串文字之间的二进制相等关系。当您将这个对象转换为字符串时,您将得到一个类似于users.name = :1的SQL片段,其中:1是参数的占位符。_BinaryExpression对象还记得:1'spam'的绑定,但是在执行SQL查询之前它不会插入它。当它被插入时,数据库引擎将确保它被正确转义。推荐阅读:SQLAlchemy's operator paradigm

如果只有数据库表,但没有描述该表的users变量,则可以自己创建该表:

代码语言:javascript
运行
复制
from sqlalchemy import Table, MetaData, Column, String, Boolean
metadata = MetaData()
users = Table('users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('email', String),
    Column('active', Integer)
)

或者,您也可以使用自动加载,它向数据库引擎查询数据库的结构并自动构建users;显然,这更耗时:

代码语言:javascript
运行
复制
users = Table('users', metadata, autoload=True)
票数 17
EN

Stack Overflow用户

发布于 2010-04-21 22:01:42

我在“SQLAlchemy: an efficient/better select by primary keys?”中也遇到了同样的问题:

代码语言:javascript
运行
复制
terms = ['one', 'two', 'three']
clauses = or_( * [Table.field == x for x in terms] )
query = Session.query(Table).filter(clauses)
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2678600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档