【问题标题】:How to update sqlalchemy orm object by a python dict如何通过 python dict 更新 sqlalchemy orm 对象
【发布时间】:2014-06-02 20:35:27
【问题描述】:

字典的键名映射到 sqlalchemy 对象属性

例如:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

可以从 id = 3、{name: "diana"} 或 id = 15、{name: "marchel", fullname: "richie marchel"} 更新

【问题讨论】:

    标签: python orm sqlalchemy


    【解决方案1】:

    您可以使用setattr() 动态更新现有 SQLAlchemy 对象的属性:

    user = session.query(User).get(someid)
    
    for key, value in yourdict.iteritems():
        setattr(user, key, value)
    

    【讨论】:

    • 这是一个带get的集合,可能有点慢?
    • @RichardWong:ORM 至少需要验证条目是否存在,并让对象有机会干扰数据(可能存在混合属性等)。当然,您可以使用 SQLAlchemy 核心创建自己的 UPDATE 语句。
    • @RichardWong:但考虑到会话在缓存和跟踪更新方面非常复杂。如果您选择绕过它,您必须确保会话缓存也无效。
    • 哎呀,意识到直接使用核心是绕过会话缓存。非常感谢你。
    • @Garrett:见documentation on Query.update();这是一个绕过 ORM 的批量更新过程。例如,如果您定义了混合属性或关系,则不会更新它们,而 setattr() 会更新它们。
    【解决方案2】:

    基于@martijn-pieters 的回答, 不仅可以用setattr动态更新列,还可以用getattrsetattr动态组合表和列

    示例:

    # models.py
    class User(Base):
        __tablename__ = 'users'
    
        id = Column(Integer, primary_key=True)
        name = Column(String)
        fullname = Column(String)
        password = Column(String)
    
    # update.py
    import models
    
    def dynamic_update(dynamic_table, col_id, dynamic_cols):
        """
        dynamic_table: name of the table, "User" for example
        col_id: id of which column you want to update
        dynamic_cols: key value pairs {name: "diana"}
        """
        if hasattr(models, dynamic_table):
            table = getattr(models, dynamic_table)
            col_info = table.query.filter_by(id=col_id).first()
            for (key, value) in dynamic_cols.items():
                if hasattr(table, key):
                    setattr(col_info, key, value)
                    session.commit()
    

    顺便说一句,您可以从 python 官方文档中获取有关 setattrgetattrhasattr 的更多信息 https://docs.python.org/2/library/functions.html#setattr

    https://docs.python.org/2/library/functions.html#getattr

    https://docs.python.org/2/library/functions.html#hasattr

    【讨论】:

    • 看起来没什么帮助,然后已经回答了问题,也许您应该解释为什么有必要这样做
    • @Gahan 我在网络上搜索,“如何动态更新sqlalchemy表和列”,但没有找到好的解决方案,从这个我知道如何动态更新列,并且使用上面的方法,我们可以更方便的更新sqlalchemy表,不仅是动态列,还有动态表。
    • 这是很好的解释,请将其添加到您的答案中
    • 警告:这将commit 对同一模型中的每个字段进行更改,如果在同一模型上更新多个字段,会显着损害性能(并且是不必要的)。
    • 是的,每更新一次字段都会commit,或许把commit放在最外层if比较好,在所有字段更新后只commit一次。
    【解决方案3】:

    我在这里有另一个解决方案。如下定义模型方法会很方便。

    class ModelName(db.Model):
        """
        docstring here
        """
        ...
    
        def update(self, **kwargs):
            for key, value in kwargs.items():
                if hasattr(self, key):
                    setattr(self, key, value)
    

    希望它能解决你的问题。

    谢谢

    【讨论】:

      【解决方案4】:

      根据您的用例(如果您不需要验证或从模型推断任何内容),您可以使用 filter_byid 保存一个 DB 调用以获取特定行,并使用像你最初想要的那样的字典。

      user_query = session.query(User).filter_by(id=someid)
      data_to_update = dict(name="marchel", fullname="richie marchel")
      
      user_query.update(data_to_update)
      

      您可能还需要在您的update 调用中添加synchronize_session=False 关键字参数,具体取决于您的会话类型(如果您使用scoped_session):

      user_query.update(data_to_update, synchronize_session=False)
      

      【讨论】:

      • 我收到“TypeError: update() got an unexpected keyword argument 'my_field'”
      • 我想在不制作真实模型的情况下更新我的 obj 上的所有属性,最后我循环遍历我想更新的对象的属性/值,并将它们添加到更新程序的值字典中, 同时跳过 Id 属性。到目前为止,这对我来说非常有效,而且非常有活力。
      【解决方案5】:

      我认为最简单的方法是使用 sqlalchemy updatefilter

      def update_item(db: Session, item_id: int, item: ItemUpdate):
          db.query(Item).filter(id=item_id).update(item.dict())
          db.commit()
      

      确保您始终对主键进行过滤,以避免更新多于一行。这可以通过在提交会话之前检查代码来完成。

      【讨论】:

        【解决方案6】:

        在 sqlalchemy 2.0 API 中,您可以使用:

        stmt = update(User).where(User.name == "john").values(**your_data)
        session.execute(stmt)
        

        【讨论】:

          猜你喜欢
          • 2016-07-17
          • 1970-01-01
          • 2021-08-28
          • 2020-06-18
          • 1970-01-01
          • 2014-06-26
          • 2021-05-22
          • 2013-03-16
          相关资源
          最近更新 更多