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了。