SQLAlchemy 最佳实践
尽量使用其 Wrapper
按照我对 SQLAlchemy 的理解,其实它的定位大概类似于:
- 一款比较偏底层 ORM lib
- 提供了一些基础了 ORM 功能,包括 SQLAlchemy Core 和 SQLAlchemy ORM
然而 Core 部分基本没有人使用。而且它对使用者暴露了太多 API,这无疑加重了使用者的心智负担,可谓之「不友好」。另外,其官方文档也有点稍显杂乱,让初学者抓不住轻重。
SQLAlchemy 使用最多的地方,大概就是与 Flask 的结合了,即 Flask-SQLAlchemy。这就是 SQLAlchemy 的 Wrapper,当然如果我们没有使用 Flask,那么就需要自己封装一层 Wrapper 了,或者使用别人已经弄好的 Wrapper。
至于为什么,如上文所述,SQLAlchemy给使用暴露的API太多,让人感到无所适从(不过如果使用得熟练了,他还是很顺手的)。
Model 之上再封装一层 Model Manager
定义完 Model 之后,马上我们就到了业务逻辑这个层次了。
没有会把一个 Model 导入到 Controller 层使用,封装一个 Manager 层是必须的( 如果必要,视业务逻辑复杂性,还可引入更多的层次)。
比如(以 Flask 为例)
user_mgr.py from SomeWhere import db from models import User class UserMgr: @classmethod def create_user(cls, **kw): u = User(**kw) db.session.add(u) db.session.commit() return u @classmethod def get_user(cls, **kw): return User.query.filter_by(**kw).first()
上层如果要操作 User,则只通过 UserMgr。
包装一个 OrmUtils
增删该查是每一个 Model 都会具有的操作,如果每个 Manager 中都写一大堆重复的create_xxx, get_xxx
,那很明显我们是在Repeat Yourself
。
首先我们会想到使用继承来解决,定义一个 BaseManager 基类,然后大家都继承它,整个过程都很符合继承的思维直觉。不过我比较偏好写各种 Utils 来解决,把通用的不变的逻辑放到 Utils 中,然后各个 Manager 将操作转发到 Utils 中。
比如:
utils/orm.py from SomeWhere import db class OrmUtils: @classmethod def create_orm(cls, orm_cls, **kw): orm = orm_cls(**kw) db.session.add(orm) db.session.commit() return orm @classmethod def get_orm(cls, orm_cls, **kw): return orm_cls.query.filter_by(**kw).first() @classmethod def delete_orm(cls, orm): orm.delete() db.session.commit() return True user_mgr.py class UserMgr: @classmethod def create_user(cls, **kw): return OrmUtils.create_orm(User, **kw)
使用一款 migration 工具
我是一个 Django 党,我对 Django 印象最深刻的就是它的 ORM 了,功能完善而且十分强大。但是对 SQLAlchemy 来说,如前文所述,它只不过是一款 Library,自然没有 Migration 工具。
但是其作者自己也写了对应的 migration 库,没有和 SQLAlchemy 整合到一起(大家可以Google下)。总的来说,还凑合,可堪一用(自然不能和Django的migration比)。
附录
- SQLAlchem 官方文档
- SQLAlchemy Wrapper 搜索结果
- SQLAlchemy 的migration库(使用搜索排名1,2的即可)