【问题标题】:Bulk update using model's method in SQLAlchemy在 SQLAlchemy 中使用模型的方法进行批量更新
【发布时间】:2023-03-16 16:05:01
【问题描述】:

我正在使用 SQLAlchemy 开发应用程序,但遇到了一些问题。我想在查询返回的所有模型上运行一个方法,并在单个 SQL 查询中完成所有操作,同时保留 ORM 提供的可读性。

所讨论的方法非常简单,不依赖任何外部数据,也不进行任何查询。如果批量更新中的所有模型都使用相同的精确值也可以,因此值本身只需要评估一次。

这是我的模型:

class Item(db.Model):
    last_fetch = db.Column(db.DateTime)

    def refresh(self):
        self.last_fetch = datetime.utcnow()

我想在查询返回的所有模型上调用 refresh() 函数 - 为了举例,我们假设它是 Item.query.all()

我可以遍历它们并在每个模型上运行该方法,但这将为每个模型运行一个单独的查询:

items = Item.query.all()

for item in items:
    item.refresh()

或者我可以执行以下操作,但是我现在已将我的 refresh() 逻辑从模型移动到否则只会调用该方法的代码:

items = Item.query.all()

items.update({Item.last_fetch: datetime.utcnow()})

有没有更好的解决方案?一种在模型上定义“智能”方法的方法,以某种方式允许 ORM 批量运行它,同时仍将其保留为模型方法?

问候。

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    由于 SQLAlchemy 不使用 __init__ 而是使用 __new__ 重新创建查询对象。
    你可以在你的模型上覆盖__new__,或者尝试看看Constructors and Object Initialization中解释的@orm.reconstructor装饰器是否可以工作。

    使用重构器:

    class Item(db.Model):
    last_fetch = db.Column(db.DateTime)
    
    @orm.reconstructor
    def set_last_fetch_on_load(self):
        self.last_fetch = datetime.datetime.now()
    

    覆盖__new__:

    class Item(db.Model):
    last_fetch = db.Column(db.DateTime)
    
    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls, *args, **kwargs)
        obj.last_fetch = datetime.datetime.now()
        return obj
    

    注意:尚未测试。

    【讨论】:

    • 这不会导致每次实例化模型时重置日期吗?那不是我想要的。我希望能够手动触发(我只在特定条件下调用它)。
    • 每次查询项目时都会更新日期。所以每次你从数据库中获取它们。如果您只需要在特定条件下执行此操作 - 我认为您所写的内容会起作用,您可以忽略我的回答。
    猜你喜欢
    • 2014-10-30
    • 2013-12-07
    • 2019-08-17
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    相关资源
    最近更新 更多