一起使用flask-sqlalchemy和sqlalchemy,为什么而且安全

时间:2019-11-17 20:02:52

标签: python flask sqlalchemy flask-sqlalchemy

我一直在开发数据库密集型的Flask应用程序,大约4个月了。我是python,flask和sqlalchemy的新手,但对Web和数据库编程非常熟悉。

我主要将核心SQL用于硬数据库位,但也使用了ORM。我与核心SQL一起使用的主要方法是text()和bindparam()函数,这些函数通过sqlalchemy方言为我提供数据库独立性。

我发现自己不得不混入我的模块导入来获得我想要的东西。这是一个简单但典型的导入。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import bindparam
from sqlalchemy.sql import text

然后,我的代码的ORM位使用了SQLAlchemy对象,并且我相信它也按照this处理会话。初始化是这样的。

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = appdb
app.config['SQLALCHEMY_BINDS'] = {'meta': foodb, 'data': bardb}
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

然后我使用db变量来访问所有flask_sqlalchemy内容。

直接的sqlalchemy东西在我的核心SQL中使用,看起来像这样。

我现在发现的是我正在混合代码,例如这样。

eng = db.get_engine(bind='meta')
cxn = eng.connect()
sql = text('select * from foo') 
rows = cxn.execute(sql).fetchall()

在我看来,如果我决定使用flask_sqlalchemy,则不必分别导入sqlalchemy内容,它应该在flask_sqlalchemy中的某个位置。混杂让我担心副作用。

所以我有两个问题。

  1. 像这样安全地混合吗?
  2. 我可以获取text()和     从bind_sqlalchemy绑定bindparam()和其他sqlalchemy的东西吗?如果     那怎么办?

1 个答案:

答案 0 :(得分:0)

以下对我自己问题的回答概括了我在过去4个月中辛苦学习的一些知识。

我是一名数据库程序员,并且希望使用SQLAlchemy核心SQL与我的数据库进行通讯,而不是ORM。下面的代码就是在这种情况下给出的。

  1. 绑定并使用多个数据库。
  2. 获取列名。
  3. 处理IN子句。
  4. 引擎v会话。
  5. 交易。

我希望它能对某人有所帮助。

'''
THE SETUP
'''
maindb = 'dialect+driver://username:password@host:port/main database'
foodb = 'dialect+driver://username:password@host:port/foo database'
bardb = 'dialect+driver://username:password@host:port/bar database'

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = maindb
app.config['SQLALCHEMY_BINDS'] = {'foodb': foodb, 'bardb': bardb}
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)


'''
THE CODE USING AN ENGINE
'''
# Using an engine (dbms = database management system).
dbms = db.get_engine(bind='foodb')
cxn = dbms.connect()
sql = db.text('SELECT * FROM foo WHERE foo_id = :id')
parms = {'id': 4}
rows = cxn.execute(sql, parms)

# Get column names, works for all the examples
print(rows.keys())

# Loop through rows and print the column value
for row in rows:
    print(row[1]) # Access by position
    print(row['foo_name']) # Access by column name
cxn.close

# Providing a list to an IN clause (bindparam with expanding=True)
sql = db.text('select * from foo where foo_id in :ids and foo_name like :nm')
parms = {'ids':[3,4,5], 'nm':'C%'}
for key in parms.keys(): # Apply bindparam to special cases like IN lists
    if type(parms[key]) == type([]): # Parameter value is a list
        sql = sql.bindparams(db.bindparam(key, expanding = True))
rows = cxn.execute(sql, parms)
print([row['foo_name'] for row in rows])

# Do a database transaction with an engine
txn = cxn.begin()
try:      
    sql = db.text('update foo set foo_name = :nm where foo_id = :id')
    parms = {'id': 4, 'nm':'mr foo bar'}
    cxn.execute(sql, parms)
    txn.commit()
except:
    txn.rollback()
    raise
finally:
    if cxn != None:
        cxn.close()

'''
THE CODE USING A SESSION
'''
# Using a session.
dbms = db.get_engine(bind='foodb')
ssn = db.session(bind=dbms)
sql = db.text('SELECT * FROM foo WHERE foo_id = :id')
parms = {'id': 4}
rows = ssn.execute(sql, parms)
print([row['foo_name'] for row in rows])

# Do a database transaction with a session
breakpoint()
try:      
    sql = db.text('update foo set foo_name = :nm where foo_id = :id')
    parms = {'id': 4, 'nm':'ms bar foo'}
    ssn.execute(sql, parms)
    ssn.commit()
except:
    ssn.rollback()
    raise
finally:
    if ssn != None:
        ssn.close()