【问题标题】:Commit changes for only one SQLAlchemy model instance when multiple have changed当多个已更改时,仅提交一个 SQLAlchemy 模型实例的更改
【发布时间】:2016-05-12 15:17:48
【问题描述】:
我查询并更改了几个实例。我只想将更改提交给其中一个。但是,当我调用db.session.commit() 时,所有更改都已提交。有没有办法单独保存一个对象,object.save(),比如 Rails 或 Django?
rule_1 = Rule.query.filter(Rule.something.like(that_thing))
rule_1.change_message = "Duplicate"
rule_2 = Rule.query.filter(Rule.something.like(that_thing))
rule_2.change_message = "This is 2nd Duplicate Message"
rule_3 = Rule.query.filter(Rule.something.like(that_thing))
rule_3.change_message = "This is the THIRD Duplicate Message"
# What I want
rule_3.save()
【问题讨论】:
标签:
python
flask
sqlalchemy
flask-sqlalchemy
【解决方案1】:
SQLAlchemy 使用工作单元模式,而 Django、Rails 和许多其他 ORM 使用活动记录模式。这意味着属于一个会话的所有内容都作为一个单元。
您的问题揭示的不是 SQLAlchemy 的问题,而是您的工作流程的问题。如果您不想更改这些值,则不应更改它们。如果您错误地更改了某些内容,请将其从会话中删除,而不是将其留在原处。
rule1.change_message = 'changed rule 1'
db.session.expunge(rule1)
# no longer part of the session, will not be committed
# use db.session.add(rule1) to track it again
如果您确实确实需要单独的工作单元(您很可能不需要),请创建单独的会话并使用它们来查询单独的实例。
Flask-SQLAlchemy 每个上下文使用一个会话,因此您的所有查询都将实例放在同一个会话中。 query 参数使用此默认会话。您可以通过调用create_session 创建单独的会话。确保手动清理这些会话。
session1 = db.create_session({})
rule1 = session1.query(Rule).filter_by(name='rule1').one()
rule1.message = 'message'
session2 = db.create_session({})
rule2 = session2.query(Rule).filter_by(name='rule2').one()
rule2.message = 'message'
session2.commit() # only commits rule2
session1.close()
session2.close()
【解决方案2】:
Rule.query 只是db.session.query(Rule) 的别名,您在同一会话中执行不同的请求,会话将作为一个整体提交。我不是专家,但要做你想做的事,你必须为每个需要的更新创建一个会话。
这可行,但我不确定这是否是最好的方法:
db = SQLAlchemy(app)
# new session created from your db instance with default parameters
new_session = db.create_session({})
rule_1 = Rule.query.filter(Rule.something.like(that_thing))
# or
# rule_1 = db.session.query(Rule).filter(Rule.something.like(that_thing))
rule_1.change_message = "Duplicate"
rule_2 = new_session.query(Rule).filter(Rule.something.like(that_thing))
rule_2.change_message = "This is 2nd Duplicate Message"
# update rule_1
db.session.commit()
# update rule_2
new_session.commit()