SQLAlchemy 建模:让数据模型承担该承担的责任

从公共字段、关系到计算属性,模型应该封装稳定的事实,而不是承载流程控制。

SQLAlchemy 建模:让数据模型承担该承担的责任

模型最常见的两个极端是:把所有逻辑塞进模型,或者把模型退化成一张纯数据表。合理的做法介于两者之间。

公共字段用 Mixin

创建时间、更新时间几乎每张表都需要:

class TimestampMixin:
    created_at = db.Column(db.DateTime, default=datetime.now)
    updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)

抽成 Mixin 后,新增模型不必重复声明,也不会出现字段命名不一致。

关系要表达领域含义

文章属于分类,文章拥有标签,标签与文章是多对多。把这些关系写在模型上,模板与服务都能直接使用:

post.tags          # [Tag(...)]
post.category.name # "架构设计"

计算属性 vs 业务操作

「阅读时长」是稳定事实,适合放在模型上:

@property
def reading_minutes(self):
    return max(1, round(len(self.content_md) / 300))

而「发布文章」涉及时间、缓存和权限,应该留在服务层。模型可以暴露 publish() 这样的小方法,但不应负责提交事务。

迁移意识

只要模型进入生产,就应该使用 Alembic 管理变更。db.create_all() 适合本地快速验证,不适合长期维护。