[英]How to execute raw SQL in Flask-SQLAlchemy app
How do you execute raw SQL in SQLAlchemy?你如何在 SQLAlchemy 中执行原始 SQL?
I have a python web app that runs on flask and interfaces to the database through SQLAlchemy.我有一个 python web 应用程序,它运行在烧瓶上,并通过 SQLAlchemy 连接到数据库。
I need a way to run the raw SQL.我需要一种运行原始 SQL 的方法。 The query involves multiple table joins along with Inline views.
该查询涉及多个表连接以及内联视图。
I've tried:我试过了:
connection = db.session.connection()
connection.execute( <sql here> )
But I keep getting gateway errors.但我不断收到网关错误。
Have you tried:你有没有尝试过:
result = db.engine.execute("<sql here>")
or:要么:
from sqlalchemy import text
sql = text('select name from penguins')
result = db.engine.execute(sql)
names = [row[0] for row in result]
print names
Note that db.engine.execute()
is "connectionless", which is deprecated in SQLAlchemy 2.0 .请注意,
db.engine.execute()
是“无连接”, 在 SQLAlchemy 2.0 中已弃用。
SQL Alchemy session objects have their own execute
method: SQL Alchemy 会话对象有自己的
execute
方法:
result = db.session.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})
All your application queries should be going through a session object, whether they're raw SQL or not.您的所有应用程序查询都应该通过会话对象,无论它们是否是原始 SQL。 This ensures that the queries are properly managed by a transaction , which allows multiple queries in the same request to be committed or rolled back as a single unit.
这确保查询由事务正确管理,这允许同一请求中的多个查询作为单个单元提交或回滚。 Going outside the transaction using the engine or the connection puts you at much greater risk of subtle, possibly hard to detect bugs that can leave you with corrupted data.
使用引擎或连接离开事务会使您面临更大的微妙风险,可能难以检测到可能导致数据损坏的错误。 Each request should be associated with only one transaction, and using
db.session
will ensure this is the case for your application.每个请求应该只与一个事务相关联,并且使用
db.session
将确保您的应用程序是这种情况。
Also take note that execute
is designed for parameterized queries .另请注意,
execute
是为参数化查询设计的。 Use parameters, like :val
in the example, for any inputs to the query to protect yourself from SQL injection attacks.对查询的任何输入使用参数,如示例中的
:val
,以保护自己免受 SQL 注入攻击。 You can provide the value for these parameters by passing a dict
as the second argument, where each key is the name of the parameter as it appears in the query.您可以通过将
dict
作为第二个参数传递来为这些参数提供值,其中每个键是在查询中出现的参数名称。 The exact syntax of the parameter itself may be different depending on your database, but all of the major relational databases support them in some form.参数本身的确切语法可能因您的数据库而异,但所有主要关系数据库都以某种形式支持它们。
Assuming it's a SELECT
query, this will return an iterable of RowProxy
objects.假设它是一个
SELECT
查询,这将返回一个可迭代的RowProxy
对象。
You can access individual columns with a variety of techniques:您可以使用多种技术访问各个列:
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
Personally, I prefer to convert the results into namedtuple
s:就个人而言,我更喜欢将结果转换为
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)
If you're not using the Flask-SQLAlchemy extension, you can still easily use a session:如果您没有使用 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})
docs: SQL Expression Language Tutorial - Using Text文档: SQL 表达式语言教程 - 使用文本
example:例子:
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')
You can get the results of SELECT SQL queries using from_statement()
and text()
as shown here .您可以使用SELECT获得SQL查询的结果
from_statement()
和text()
如图所示这里。 You don't have to deal with tuples this way.您不必以这种方式处理元组。 As an example for a class
User
having the table name users
you can try,作为具有表名
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>"))
executes the <sql here>
but doesn't commit it unless you're on autocommit
mode.执行
<sql here>
但除非您处于autocommit
模式,否则不会提交它。 So, inserts and updates wouldn't reflect in the database.因此,插入和更新不会反映在数据库中。
To commit after the changes, do要在更改后提交,请执行
result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))
Starting in SQLAlchemy 1.4, connectionless or implicit execution has been deprecated, ie从 SQLAlchemy 1.4 开始,不推荐使用无连接或隐式执行,即
db.engine.execute(...) # DEPRECATED
as well as bare strings as queries.以及作为查询的裸字符串。
The new API requires an explicit connection, eg新 API 需要显式连接,例如
from sqlalchemy import text
with db.engine.connect() as connection:
result = connection.execute(text("SELECT * FROM ..."))
for row in result:
# ...
Similarly, it's encouraged to use an existing Session if one is available:同样,如果有可用的会话,则鼓励使用现有会话:
result = session.execute(sqlalchemy.text("SELECT * FROM ..."))
or using parameters:或使用参数:
session.execute(sqlalchemy.text("SELECT * FROM a_table WHERE a_column = :val"),
{'val': 5})
See " Connectionless Execution, Implicit Execution " in the documentation for more details.有关更多详细信息,请参阅文档中的“无连接执行,隐式执行”。
This is a simplified answer of how to run SQL query from Flask Shell
这是如何从 Flask Shell 运行 SQL 查询的简化答案
First, map your module (if your module/app is manage.py in the principal folder and you are in a UNIX Operating system), run:首先,映射您的模块(如果您的模块/应用程序是主体文件夹中的 manage.py 并且您在 UNIX 操作系统中),运行:
export FLASK_APP=manage
Run Flask shell运行烧瓶外壳
flask shell
Import what we need::导入我们需要的东西::
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
from sqlalchemy import text
Run your query:运行您的查询:
result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))
This use the currently database connection which has the application.这使用具有应用程序的当前数据库连接。
Have you tried using connection.execute(text( <sql here> ), <bind params here> )
and bind parameters as described in the docs ?您是否尝试过使用
connection.execute(text( <sql here> ), <bind params here> )
和文档中描述的绑定参数? This can help solve many parameter formatting and performance problems.这可以帮助解决许多参数格式和性能问题。 Maybe the gateway error is a timeout?
也许网关错误是超时? Bind parameters tend to make complex queries execute substantially faster.
绑定参数往往会使复杂查询的执行速度大大加快。
If you want to avoid tuples, another way is by calling the first
, one
or all
methods:如果您想避免使用元组,另一种方法是调用
first
、 one
或all
方法:
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.