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