使用 sql alchemy 查询是否有一种方法可以遍历 table 中的所有列
With sql alchemy query is there a way to iterate over all columns in a table
我想在链接到 5 tables 数据库的网页上创建一个搜索功能。
这个想法是,用户可以 select table 进行搜索并输入搜索词,它会 return 一个结果列表。
显然我可以使用 5 个 if 语句来做到这一点,但似乎应该有更简单的方法。
这段代码是我尝试过的代码,但出于某种原因,当我将 item
和 table
变量而不是实际的列名称放入查询中时,它不起作用。仅当我在 table
和 table.item
.
中键入特定术语时才有效
if 'form.submitted' in request.params:
#search term
search = request.params['body']
#table to be searched
table = request.params['table']
list = eval(table).__table__.columns._data.keys()
results = {}
for item in list:
try:
searchdb = request.dbsession.query(table).filter(table.item==search).all()
results[item]=searchdb
except:
continue
return (results)
我想知道这是否可行,或者我应该放弃并写 5 个 if 语句
请不要使用list
(内置类型)命名variables/identifiers。
...
if ...
table = eval(request.params['table']).__table__ # <-- find a better way to create table instance
results = {}
for col in table.c:
try:
searchdb = request.dbsession.query(table).filter(col == search).all()
results[item] = searchdb
except:
continue
return results
请不要使用eval()
、it is mostly evil. You cannot use it safely on user input, as shown in "Eval really is dangerous"。想象一下,一个对手正在呼叫您的 API,而不是使用您的表单或类似的方式,只是向您发送类似于
的内容
body=byebye&table=__import__("os").system("rm -rf /")
根据您的设置,您可能会丢失整个系统、容器或您拥有的东西。而这并不是他们唯一能做的。他们有整个 Python 表达式可以玩。
在您的情况下,处理用户选择的 tables(模型)的正确方法是进行查找:
the_5_tables = {
"table_1": Table1,
"table_2": Table2,
# etc.
}
那么你需要做的就是
#table to be searched
model = the_5_tables[request.params['table']]
这有一个额外的好处,即可以将 table 用户可以使用的内容列入白名单,即使当前范围可以访问其他人。
使用实际的 Column
对象而不是它们的键可以更轻松地生成过滤器:
results = {}
for col in model.__table__.columns:
try:
searchdb = request.dbsession.query(model).filter(col == search).all()
results[col.key] = searchdb
except Exception as e:
print(f"Unhandled error: {e}")
continue
return results
不幸的是,这将与您 table 中的列一样多地往返数据库。现在,我猜 except:
是为了掩盖类型不匹配引起的错误,例如当您尝试搜索数字列时。您可以进一步检查列以避免:
from sqlalchemy.types import String
# ...
results = {}
for col in model.__table__.columns:
if isinstance(col.type, String):
searchdb = request.dbsession.query(model).filter(col == search).all()
results[col.key] = searchdb
return results
更进一步,如果您实际上对匹配的列不那么感兴趣,您可以只形成一个查询,例如:
from sqlalchemy import literal
from sqlalchemy.types import String
# ...
str_cols = [c for c in model.__table__.c if isinstance(c.type, String)]
results = request.dbsession.query(model).filter(literal(search).in_(str_cols)).all()
return results
虽然有点 hacky,但仍然可以在单个查询中获取匹配的列(这不是很有用;在查询后在 Python 中执行相同的操作很简单):
from sqlalchemy import func
# ...
results = request.dbsession.query(
model,
func.concat_ws(",", *[
func.if_(c == search, c.key, None)
for c in str_cols
]).label("in_columns")).\
filter(literal(search).in_(str_cols)).all()
return results
in_columns
将是匹配的列名称的逗号分隔字符串。
我想在链接到 5 tables 数据库的网页上创建一个搜索功能。
这个想法是,用户可以 select table 进行搜索并输入搜索词,它会 return 一个结果列表。
显然我可以使用 5 个 if 语句来做到这一点,但似乎应该有更简单的方法。
这段代码是我尝试过的代码,但出于某种原因,当我将 item
和 table
变量而不是实际的列名称放入查询中时,它不起作用。仅当我在 table
和 table.item
.
if 'form.submitted' in request.params:
#search term
search = request.params['body']
#table to be searched
table = request.params['table']
list = eval(table).__table__.columns._data.keys()
results = {}
for item in list:
try:
searchdb = request.dbsession.query(table).filter(table.item==search).all()
results[item]=searchdb
except:
continue
return (results)
我想知道这是否可行,或者我应该放弃并写 5 个 if 语句
请不要使用list
(内置类型)命名variables/identifiers。
...
if ...
table = eval(request.params['table']).__table__ # <-- find a better way to create table instance
results = {}
for col in table.c:
try:
searchdb = request.dbsession.query(table).filter(col == search).all()
results[item] = searchdb
except:
continue
return results
请不要使用eval()
、it is mostly evil. You cannot use it safely on user input, as shown in "Eval really is dangerous"。想象一下,一个对手正在呼叫您的 API,而不是使用您的表单或类似的方式,只是向您发送类似于
body=byebye&table=__import__("os").system("rm -rf /")
根据您的设置,您可能会丢失整个系统、容器或您拥有的东西。而这并不是他们唯一能做的。他们有整个 Python 表达式可以玩。
在您的情况下,处理用户选择的 tables(模型)的正确方法是进行查找:
the_5_tables = {
"table_1": Table1,
"table_2": Table2,
# etc.
}
那么你需要做的就是
#table to be searched
model = the_5_tables[request.params['table']]
这有一个额外的好处,即可以将 table 用户可以使用的内容列入白名单,即使当前范围可以访问其他人。
使用实际的 Column
对象而不是它们的键可以更轻松地生成过滤器:
results = {}
for col in model.__table__.columns:
try:
searchdb = request.dbsession.query(model).filter(col == search).all()
results[col.key] = searchdb
except Exception as e:
print(f"Unhandled error: {e}")
continue
return results
不幸的是,这将与您 table 中的列一样多地往返数据库。现在,我猜 except:
是为了掩盖类型不匹配引起的错误,例如当您尝试搜索数字列时。您可以进一步检查列以避免:
from sqlalchemy.types import String
# ...
results = {}
for col in model.__table__.columns:
if isinstance(col.type, String):
searchdb = request.dbsession.query(model).filter(col == search).all()
results[col.key] = searchdb
return results
更进一步,如果您实际上对匹配的列不那么感兴趣,您可以只形成一个查询,例如:
from sqlalchemy import literal
from sqlalchemy.types import String
# ...
str_cols = [c for c in model.__table__.c if isinstance(c.type, String)]
results = request.dbsession.query(model).filter(literal(search).in_(str_cols)).all()
return results
虽然有点 hacky,但仍然可以在单个查询中获取匹配的列(这不是很有用;在查询后在 Python 中执行相同的操作很简单):
from sqlalchemy import func
# ...
results = request.dbsession.query(
model,
func.concat_ws(",", *[
func.if_(c == search, c.key, None)
for c in str_cols
]).label("in_columns")).\
filter(literal(search).in_(str_cols)).all()
return results
in_columns
将是匹配的列名称的逗号分隔字符串。