Flask-SQLAlchemy下的Pandas read_sql数据库引擎
我正在用Flask写一个网页应用,并且使用pandas从MySQL数据库中获取数据。之前我看到的一个帖子里提到的方法是这样的:
db = SQLAlchemy()
app = Flask(__name__)
app.config.from_object(config['default'])
db.init_app(app)
conn = db.engine.connect().connection
然后在视图函数里(在同一个.py文件中):
@app.route('/report', methods=['GET', 'POST'])
def report():
form = ReportForm()
...
sql = '''SELECT * FROM availability ...'''
df = psql.read_sql(sql, conn)
...
return render_template('report.html', form=form, df=df)
这个网页会根据用户在表单中选择的日期范围显示一个表格。我在网页上通过x-editable添加了对这个表格的在线编辑功能,我看到修改已经成功保存到数据库里,但如果我再次提交表单,表格只会加载修改之前的旧数据。只有在我重新打开网页后才能看到更改,这真是太奇怪了。
把'conn'这一行放在read_sql之前就能正常工作:
sql = '''SELECT * FROM availability ...'''
conn = db.engine.connect().connection
df = psql.read_sql(sql, conn)
但这样做不太好,因为我每次查询都得重复这个步骤(每个视图都有几个查询)。有没有办法让我只在一开始声明这个连接对象,然后就不用再管它了?虽然SQLAlchemy的ORM可以用,但在这种情况下我更喜欢直接写原始SQL。
编辑:
joris的建议对一个查询有效,但我现在遇到了另一个错误:
File "C:\Users\KF\flask-test\hello.py", line 107, in report
df = pd.read_sql_query(sql.format(vd='20140727', sd=sd, ed=ed), db.engine)
File "C:\Anaconda\envs\lightson\lib\site-packages\pandas\io\sql.py", line 363, in read_sql_query
parse_dates=parse_dates)
File "C:\Anaconda\envs\lightson\lib\site-packages\pandas\io\sql.py", line 823, in read_sql
result = self.execute(*args)
File "C:\Anaconda\envs\lightson\lib\site-packages\pandas\io\sql.py", line 810, in execute
return self.engine.execute(*args, **kwargs)
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\base.py", line 1752, in execute
return connection.execute(statement, *multiparams, **params)
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\base.py", line 721, in execute
return self._execute_text(object, multiparams, params)
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\base.py", line 870, in _execute_text
statement, parameters
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\base.py", line 958, in _execute_context
context)
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\base.py", line 1163, in _handle_dbapi_exception
util.reraise(*exc_info)
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\base.py", line 951, in _execute_context
context)
File "C:\Anaconda\envs\lightson\lib\site-packages\sqlalchemy\engine\default.py", line 436, in do_execute
cursor.execute(statement, parameters)
File "c:\users\kf\appdata\local\temp\easy_install-_444w8\MySQL_python-1.2.5-py2.7-win-amd64.egg.tmp\MySQLdb\cursors.py", line 187, in execute
query = query % tuple([db.literal(item) for item in args])
TypeError: not enough arguments for format string
不过原始的SQL字符串是没问题的——我自己运行过这个查询,结果是有效的。实际的SQL是:
sql = '''SELECT * FROM availability WHERE view_date = str_to_date('{vd}', '%Y%m%d') and book_date >= str_to_date('{sd}','%Y%m%d') and book_date <= str_to_date('{ed}', '%Y%m%d')'''
这里的'sd'和'ed'是看起来像'20140801'的字符串。看起来我得为MySQL转义这些'%'符号,但我找不到方法。
编辑:
我搞定了。只需在'%Y'、'%m'和'%d'前面再加一个'%'来转义百分号。基本上,正如joris所说,使用pd.read_sql_query
就可以了。
1 个回答
5
我搞明白了。对于将来可能需要这个的人:
1. 在'%Y'、'%m'和'%d'前面再加一个'%',这样可以让百分号正常显示。
2. 就像joris说的,使用pd.read_sql_query
,而不是read_sql
。