首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用sql alchemy query,有没有一种方法可以迭代表中的所有列

使用sql alchemy query,有没有一种方法可以迭代表中的所有列
EN

Stack Overflow用户
提问于 2019-07-16 01:24:30
回答 2查看 793关注 0票数 1

我想在我的网页上创建一个搜索功能,这是链接到数据库的5个表。

其思想是,用户可以选择要搜索的表并输入搜索词,它将返回一个结果列表。

显然,我可以通过使用5个if语句来做到这一点,但似乎应该有一种更简单的方法。

这是我尝试过的代码,但是由于某些原因,当我将itemtable变量而不是实际的列名放入查询中时,它不起作用。只有当我在tabletable.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语句。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-16 02:41:36

请不要使用eval()it is mostly evil。您不能在用户输入时安全地使用它,如"Eval really is dangerous"中所示。想象一下,一个对手正在调用您的API,而不是使用您的表单或诸如此类的东西,只是向您发送类似以下内容的内容

body=byebye&table=__import__("os").system("rm -rf /")

根据您的设置,您可能会丢失整个系统,或者容器,或者您所拥有的一切。这并不是他们唯一能做的事情。他们有完整的Python表达式可以使用。

在您的示例中,处理用户选择的表(模型)的适当方法是使用查找:

the_5_tables = {
    "table_1": Table1,
    "table_2": Table2,
    # etc.
}

那么你需要做的就是

#table to be searched
model = the_5_tables[request.params['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

不幸的是,这将使数据库的往返次数与表中的列一样多。现在,我猜测空的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

虽然有点老生常谈,但仍然可以在单个查询中获取匹配的列(这不是很有用;在查询之后用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将是一个逗号分隔的匹配列名字符串。

票数 3
EN

Stack Overflow用户

发布于 2019-07-16 01:38:28

请不要使用list (内置类型)来命名变量/标识符。

...
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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57044531

复制
相关文章

相似问题

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