SQLAlchemy 最佳实践

尽量使用其 Wrapper

按照我对 SQLAlchemy 的理解,其实它的定位大概类似于:

  1. 一款比较偏底层 ORM lib
  2. 提供了一些基础了 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的即可)

相关推荐