简体   繁体   English

如何在 Flask-SQLAlchemy 应用程序中执行原始 SQL

[英]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))

For SQLAlchemy ≥ 1.4对于 SQLAlchemy ≥ 1.4

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:如果您想避免使用元组,另一种方法是调用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