You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLModel优化:如何简化__init__与update中自定义方法调用语法?

实现@run_on_change装饰器

要简化SQLModel实例创建/更新时的自定义逻辑调用,我们可以通过方法标记+自定义元类的方式实现目标装饰器,彻底消除样板代码。

1. 定义标记装饰器

先写一个轻量装饰器,给需要触发的方法打上标记:

def run_on_change(func):
    func._is_run_on_change = True
    return func

2. 自定义元类注入逻辑

继承SQLModel的元类,在类创建阶段收集标记方法,并重写__init__和update方法:

from sqlmodel import SQLModel
from sqlmodel.main import SQLModelMeta

class RunOnChangeMeta(SQLModelMeta):
    def __new__(cls, name, bases, namespace):
        # 收集所有标记了_run_on_change的方法
        change_methods = [
            method for _, method in namespace.items()
            if hasattr(method, "_is_run_on_change")
        ]
        
        # 重写__init__
        original_init = namespace.get("__init__")
        def new_init(self, **kwargs):
            original_init(self, **kwargs) if original_init else super(self.__class__, self).__init__(**kwargs)
            for method in change_methods:
                method(self)
        
        # 重写update
        original_update = namespace.get("update")
        def new_update(self, **kwargs):
            original_update(self, **kwargs) if original_update else super(self.__class__, self).update(**kwargs)
            for method in change_methods:
                method(self)
        
        namespace["__init__"] = new_init
        namespace["update"] = new_update
        return super().__new__(cls, name, bases, namespace)

3. 创建通用基类

基于自定义元类创建基类,后续模型直接继承即可:

class BaseModel(SQLModel, metaclass=RunOnChangeMeta):
    pass

4. 模型中使用示例

现在可以用简洁的语法实现需求:

class MyModel(BaseModel, table=True):
    id: int | None = None
    name: str
    computed_field: str | None = None

    @run_on_change
    def custom_method(self):
        """创建或更新时自动执行的逻辑"""
        self.computed_field = self.name.upper()

测试验证:

# 创建实例触发逻辑
obj = MyModel(name="test")
print(obj.computed_field)  # 输出 TEST

# 更新实例触发逻辑
obj.update(name="new test")
print(obj.computed_field)  # 输出 NEW TEST

是否用@listens_for替代?

SQLModel基于SQLAlchemy,@listens_for是SQLAlchemy的事件监听工具,和当前方案的核心差异在于触发时机:

  • 自定义装饰器方案:作用于内存层面,只要调用__init__或update就触发,不管是否涉及数据库操作。适合纯内存逻辑(如计算字段、内存数据验证)。
  • @listens_for方案:作用于数据库操作层面,仅在执行insert/update等数据库指令时触发(如before_insert/before_update事件)。适合和数据库强绑定的逻辑(如入库前数据校验、同步关联表数据)。

如果你的逻辑不需要和数据库操作绑定,自定义装饰器方案更直接;如果逻辑必须在数据库写入前执行,@listens_for是更合适的选择。

内容的提问来源于stack exchange,提问作者charrison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:06:26