【问题标题】:Flask-SQLalchemy update a row's informationFlask-SQLalchemy 更新一行的信息
【发布时间】:2011-07-14 20:11:36
【问题描述】:

如何更新行的信息?

例如,我想更改 id 为 5 的行的名称列。

【问题讨论】:

    标签: python sqlalchemy flask-sqlalchemy


    【解决方案1】:

    使用tutorial shown in the Flask-SQLAlchemy documentation 检索对象。拥有要更改的实体后,请更改实体本身。然后,db.session.commit()

    例如:

    admin = User.query.filter_by(username='admin').first()
    admin.email = 'my_new_email@example.com'
    db.session.commit()
    
    user = User.query.get(5)
    user.name = 'New Name'
    db.session.commit()
    

    Flask-SQLAlchemy 基于 SQLAlchemy,因此请务必同时查看 SQLAlchemy Docs

    【讨论】:

    • 谢谢马克。另一件事。我已经看到它像这样'db.add(user)'然后'dv.session.commit()'。为什么两者都有效?有什么区别?
    • 这与 SQLAlchemy 中瞬态、分离和附加对象之间的差异有关(请参阅sqlalchemy.org/docs/orm/session.html#what-does-the-session-do)。此外,请阅读 Michael Bayer 在邮件列表 (groups.google.com/group/sqlalchemy/browse_thread/thread/…) 上的评论以获取更多信息。
    • 如果您在阅读完之后仍然对差异感到困惑,请考虑再问一个问题。
    • 如果列数据类型是json,使用下面的方法。 bashelton.com/2014/03/…
    • @MarkHildreth 我无法将日期时间值更新到该字段,我该怎么办?列是 uesd_at = db.Column(db.DateTime) 我只是运行 obj.used_at = datetime.datetime.now() db.session.commit() 但没有为该字段设置值。
    【解决方案2】:

    仅分配值并提交它们将适用于所有数据类型,但 JSON 和 Pickled 属性除外。由于上面解释了腌制类型,我将记下一种稍微不同但简单的更新 JSON 的方法。

    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(80), unique=True)
        data = db.Column(db.JSON)
    
    def __init__(self, name, data):
        self.name = name
        self.data = data
    

    假设模型如上。

    user = User("Jon Dove", {"country":"Sri Lanka"})
    db.session.add(user)
    db.session.flush()
    db.session.commit()
    

    这会将用户添加到 MySQL 数据库中,数据为 {"country":"Sri Lanka"}

    修改数据将被忽略。我的不起作用的代码如下。

    user = User.query().filter(User.name=='Jon Dove')
    data = user.data
    data["province"] = "south"
    user.data = data
    db.session.merge(user)
    db.session.flush()
    db.session.commit()
    

    与其经历将 JSON 复制到新 dict 的痛苦工作(而不是像上面那样将其分配给新变量),这应该可行,我找到了一种简单的方法来做到这一点。有一种方法可以标记 JSON 已更改的系统。

    以下是工作代码。

    from sqlalchemy.orm.attributes import flag_modified
    user = User.query().filter(User.name=='Jon Dove')
    data = user.data
    data["province"] = "south"
    user.data = data
    flag_modified(user, "data")
    db.session.merge(user)
    db.session.flush()
    db.session.commit()
    

    这就像一个魅力。 与此方法一起提出了另一种方法here 希望我对某人有所帮助。

    【讨论】:

    • db.session.merge(user) 添加此代码对我有用,仅供参考。
    • 谢谢,这就是我要找的东西
    【解决方案3】:

    SQLAlchemy中BaseQuery对象有一个方法update,由filter_by返回。

    num_rows_updated = User.query.filter_by(username='admin').update(dict(email='my_new_email@example.com')))
    db.session.commit()
    

    使用update 相对于更改实体的优势在于要更新的​​对象很多。

    如果您想将add_user 权限授予所有admins,

    rows_changed = User.query.filter_by(role='admin').update(dict(permission='add_user'))
    db.session.commit()
    

    请注意,filter_by 采用关键字参数(仅使用一个 =),而 filter 采用表达式。

    【讨论】:

    • 在第一个查询中,结果被命名为admin,这可能会产生误导,因为结果将是更新的行数。不是吗?
    • 有没有办法通过查询获得受影响的User 项目,而不是受影响的用户数量?
    • 行数匹配
    • 为什么需要将变量'admin'传递给更新函数?它没有在任何地方使用
    【解决方案4】:

    Models.py 定义序列化器

    def default(o):
       if isinstance(o, (date, datetime)):
          return o.isoformat()
    
    def get_model_columns(instance,exclude=[]):
        columns=instance.__table__.columns.keys()
        columns=list(set(columns)-set(exclude))
        return columns
    
    class User(db.Model):
       __tablename__='user'
       id = db.Column(db.Integer, primary_key=True, autoincrement=True)
       .......
       ####
    
        def serializers(self):
           cols = get_model_columns(self)
           dict_val = {}
           for c in cols:
               dict_val[c] = getattr(self, c)
           return json.loads(json.dumps(dict_val,default=default))
    

    在RestApi中,我们可以通过将json数据传递给更新查询来动态更新记录:

    class UpdateUserDetails(Resource):
       @auth_token_required
       def post(self):
          json_data = request.get_json()
          user_id = current_user.id
          try:
             instance = User.query.filter(User.id==user_id)
             data=instance.update(dict(json_data))
             db.session.commit()
             updateddata=instance.first()
             msg={"msg":"User details updated successfully","data":updateddata.serializers()}
             code=200
          except Exception as e:
             print(e)
             msg = {"msg": "Failed to update the userdetails! please contact your administartor."}
             code=500
          return msg
    

    【讨论】:

    • 它简短而最好!
    • 我使用您的实例方法@Ramesh Ponnusamy 更新了长字典数据并在过程中学习它。谢谢
    【解决方案5】:

    如果您修改模型的腌制属性,这将不起作用。腌制的属性应该被替换以触发更新:

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    from pprint import pprint
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqllite:////tmp/users.db'
    db = SQLAlchemy(app)
    
    
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(80), unique=True)
        data = db.Column(db.PickleType())
    
        def __init__(self, name, data):
            self.name = name
            self.data = data
    
        def __repr__(self):
            return '<User %r>' % self.username
    
    db.create_all()
    
    # Create a user.
    bob = User('Bob', {})
    db.session.add(bob)
    db.session.commit()
    
    # Retrieve the row by its name.
    bob = User.query.filter_by(name='Bob').first()
    pprint(bob.data)  # {}
    
    # Modifying data is ignored.
    bob.data['foo'] = 123
    db.session.commit()
    bob = User.query.filter_by(name='Bob').first()
    pprint(bob.data)  # {}
    
    # Replacing data is respected.
    bob.data = {'bar': 321}
    db.session.commit()
    bob = User.query.filter_by(name='Bob').first()
    pprint(bob.data)  # {'bar': 321}
    
    # Modifying data is ignored.
    bob.data['moo'] = 789
    db.session.commit()
    bob = User.query.filter_by(name='Bob').first()
    pprint(bob.data)  # {'bar': 321}
    

    【讨论】:

    • 在这种情况下最好的方法是什么?
    • 您必须复制 data 并重新分配它。
    • @sas 你什么意思?
    • 您需要复制并分配给 data 属性以触发更新机制。看看下面的答案:user.data = data
    • 为什么在您的示例中忽略了修改数据? @Bevan
    【解决方案6】:

    我正在寻找比@Ramesh 的回答(这很好)但仍然充满活力的东西。这是一个将更新方法附加到 db.Model 对象的解决方案。

    你传入一个字典,它只会更新你传入的列。

    class SampleObject(db.Model):
      id = db.Column(db.BigInteger, primary_key=True)
      name = db.Column(db.String(128), nullable=False)
      notes = db.Column(db.Text, nullable=False)
    
      def update(self, update_dictionary: dict):
        for col_name in self.__table__.columns.keys():
          if col_name in update_dictionary:
            setattr(self, col_name, update_dictionary[col_name])
    
        db.session.add(self)
        db.session.commit()
    

    然后在一条路线上你可以做

    object = SampleObject.query.where(SampleObject.id == id).first()
    object.update(update_dictionary=request.get_json())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-03
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      • 2018-09-06
      • 1970-01-01
      • 2021-07-10
      • 2018-05-14
      相关资源
      最近更新 更多