Aiohttp 下使用 SQLAlchemy 和 Aiomysql 需要注意的一些问题
根据 Aiohttp 官方文档教程学习,在使用 Aiomysql 配合 SQLAlchemy 时,我遇到了两个十分坑爹的问题,白白折腾了好几个小时。而在各大搜索引擎里也没有解答,于是写下这篇文章希望对以后踩坑的人有些帮助。
id 为自增主键,insert 报错
首先在表的定义为如下:
users = Table(
'users', meta,
Column('id', Integer, primary_key=True),
Column('name', String(32), nullable=False, unique=True, server_default=text("'0'")),
Column('password', String(80), nullable=False, server_default=text("'0'")),
)
aiohttp 官方教程中 init_db.py 的代码配合以上表:
from settings import config
from blog.models import users
DSN = "mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
def sample_data(engine):
conn = engine.connect()
conn.execute(users.insert(), [
{'name': 'veoco',
'password':'123456',
])
conn.close()
if __name__ == '__main__':
db_url = DSN.format(**config['mysql'])
engine = create_engine(db_url)
sample_data(engine)
默认情况下 id 即为自增,在这种情况下插入语句应该可以省略 id。事实也是如此,按照 Aiohttp 教程中的 init_db.py 流程插入毫无问题,但按照教程从 app 取出 engine 插入就会报错:sqlalchemy.exc.InvalidRequestError: A value is required for bind parameter 'id'
。
报错说明必须要有 id 的参数,但是 id 原本就是自增不应该手动插入,解决的方法就是添加 id 参数,只不过参数为 None,我的代码如下:
async with request.app['db'].acquire() as conn:
await conn.execute(users.insert(), [
{'id': None,
'name': username,
'password': password,
])
由此,主键自增情况下插入报错的问题解决了,这时又发现了一个新问题。
aiomysql 执行后没有生效
除去前面增加的 id 这列,不知道你有没有发现两处代码的不一样。答案就是 engine,init_db.py 中为 engine.connect()
而在 aiohttp 教程中为 engine.accquire()
,这两者实现并不一样,后者在 select 时无需额外动作,而在 insert 时需要在之后 commit,添加后的代码如下:
async with request.app['db'].acquire() as conn:
await conn.execute(users.insert(), [
{'id': None,
'name': username,
'password': password,
])
await conn.execute('commit')
由此终于可以在 Aiohttp 下愉快的使用 Aiomysql 和 SQLAlchemy 了。