簡體   English   中英

如何在 Flask-SQLAlchemy 應用程序中執行原始 SQL

[英]How to execute raw SQL in Flask-SQLAlchemy app

你如何在 SQLAlchemy 中執行原始 SQL?

我有一個 python web 應用程序,它運行在燒瓶上,並通過 SQLAlchemy 連接到數據庫。

我需要一種運行原始 SQL 的方法。 該查詢涉及多個表連接以及內聯視圖。

我試過了:

connection = db.session.connection()
connection.execute( <sql here> )

但我不斷收到網關錯誤。

你有沒有嘗試過:

result = db.engine.execute("<sql here>")

要么:

from sqlalchemy import text

sql = text('select name from penguins')
result = db.engine.execute(sql)
names = [row[0] for row in result]
print names

請注意, db.engine.execute()是“無連接”, 在 SQLAlchemy 2.0 中已棄用

SQL Alchemy 會話對象有自己的execute方法:

result = db.session.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

您的所有應用程序查詢都應該通過會話對象,無論它們是否是原始 SQL。 這確保查詢由事務正確管理,這允許同一請求中的多個查詢作為單個單元提交或回滾。 使用引擎連接離開事務會使您面臨更大的微妙風險,可能難以檢測到可能導致數據損壞的錯誤。 每個請求應該只與一個事務相關聯,並且使用db.session將確保您的應用程序是這種情況。

另請注意, execute是為參數化查詢設計的。 對查詢的任何輸入使用參數,如示例中的:val ,以保護自己免受 SQL 注入攻擊。 您可以通過將dict作為第二個參數傳遞來為這些參數提供值,其中每個鍵是在查詢中出現的參數名稱。 參數本身的確切語法可能因您的數據庫而異,但所有主要關系數據庫都以某種形式支持它們。

假設它是一個SELECT查詢,這將返回一個可迭代RowProxy對象。

您可以使用多種技術訪問各個列:

for r in result:
    print(r[0]) # Access by positional index
    print(r['my_column']) # Access by column name as a string
    r_dict = dict(r.items()) # convert to dict keyed by column names

就個人而言,我更喜歡將結果轉換為namedtuple s:

from collections import namedtuple

Record = namedtuple('Record', result.keys())
records = [Record(*r) for r in result.fetchall()]
for r in records:
    print(r.my_column)
    print(r)

如果您沒有使用 Flask-SQLAlchemy 擴展,您仍然可以輕松使用會話:

import sqlalchemy
from sqlalchemy.orm import sessionmaker, scoped_session

engine = sqlalchemy.create_engine('my connection string')
Session = scoped_session(sessionmaker(bind=engine))

s = Session()
result = s.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

文檔: SQL 表達式語言教程 - 使用文本

例子:

from sqlalchemy.sql import text

connection = engine.connect()

# recommended
cmd = 'select * from Employees where EmployeeGroup = :group'
employeeGroup = 'Staff'
employees = connection.execute(text(cmd), group = employeeGroup)

# or - wee more difficult to interpret the command
employeeGroup = 'Staff'
employees = connection.execute(
                  text('select * from Employees where EmployeeGroup = :group'), 
                  group = employeeGroup)

# or - notice the requirement to quote 'Staff'
employees = connection.execute(
                  text("select * from Employees where EmployeeGroup = 'Staff'"))


for employee in employees: logger.debug(employee)
# output
(0, 'Tim', 'Gurra', 'Staff', '991-509-9284')
(1, 'Jim', 'Carey', 'Staff', '832-252-1910')
(2, 'Lee', 'Asher', 'Staff', '897-747-1564')
(3, 'Ben', 'Hayes', 'Staff', '584-255-2631')

您可以使用SELECT獲得SQL查詢的結果from_statement()text()如圖所示這里 您不必以這種方式處理元組。 作為具有表名users的類User的示例,您可以嘗試,

from sqlalchemy.sql import text

user = session.query(User).from_statement(
    text("""SELECT * FROM users where name=:name""")
).params(name="ed").all()

return user
result = db.engine.execute(text("<sql here>"))

執行<sql here>但除非您處於autocommit模式,否則不會提交它。 因此,插入和更新不會反映在數據庫中。

要在更改后提交,請執行

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

對於 SQLAlchemy ≥ 1.4

從 SQLAlchemy 1.4 開始,不推薦使用無連接或隱式執行,即

db.engine.execute(...) # DEPRECATED

以及作為查詢的裸字符串。

新 API 需要顯式連接,例如

from sqlalchemy import text

with db.engine.connect() as connection:
    result = connection.execute(text("SELECT * FROM ..."))
    for row in result:
        # ...

同樣,如果有可用的會話,則鼓勵使用現有會話

result = session.execute(sqlalchemy.text("SELECT * FROM ..."))

或使用參數:

session.execute(sqlalchemy.text("SELECT * FROM a_table WHERE a_column = :val"),
                {'val': 5})

有關更多詳細信息請參閱文檔中的“無連接執行,隱式執行”。

這是如何從 Flask Shell 運行 SQL 查詢的簡化答案

首先,映射您的模塊(如果您的模塊/應用程序是主體文件夾中的 manage.py 並且您在 UNIX 操作系統中),運行:

export FLASK_APP=manage

運行燒瓶外殼

flask shell

導入我們需要的東西::

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
from sqlalchemy import text

運行您的查詢:

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

這使用具有應用程序的當前數據庫連接。

您是否嘗試過使用connection.execute(text( <sql here> ), <bind params here> )文檔中描述的綁定參數? 這可以幫助解決許多參數格式和性能問題。 也許網關錯誤是超時? 綁定參數往往會使復雜查詢的執行速度大大加快。

如果您想避免使用元組,另一種方法是調用firstoneall方法:

query = db.engine.execute("SELECT * FROM blogs "
                           "WHERE id = 1 ")

assert query.first().name == "Welcome to my blog"

暫無
暫無

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

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