簡體   English   中英

使用sql alchemy查詢有一種方法來迭代表中的所有列

[英]With sql alchemy query is there a way to iterate over all columns in a table

我想在我的網頁上創建一個鏈接到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語句

請不要使用eval()它主要是邪惡的 您不能安全地在用戶輸入上使用它,如“Eval確實很危險”中所示 想象一下,如果一個對手正在調用你的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

雖然有點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將是一個逗號分隔的匹配的列名字符串。

請勿使用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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM