如何更新SQLAlchemy行的某些列而不更改未指定的列?

2024-10-02 14:22:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一张三行的桌子,像这样:

| serverID | behavior  | limit  |
---------------------------------
| 102      | action1   | 5      |
| 103      | action2   | 8      |

我这里有一个函数:

def set_warn_settings(serverID, behavior, limit):
with INSERTION_LOCK:
    try:
        row = SESSION.query(WarnSettings).filter(WarnSettings.serverID == serverID).first()
        if row:
            row.behavior = behavior
            row.limit = limit

            SESSION.add(row)
            SESSION.commit()
        else:
            action = WarnSettings(serverID, behavior, limit)

            SESSION.add(action)
            SESSION.commit()
    finally:
        SESSION.close()

当我调用函数并且其中一个参数是None时,列的值将被None替换,而不是像以前那样保留它。有时调用函数时,只有一个参数不是None。你知道吗

如何更新某个列的值,同时保持其余列不受影响,全部来自一个函数?你知道吗


Tags: 函数noneadd参数sessionactionrowcommit
2条回答

处理这个问题的一种方法是在函数签名中使用^{}构造。然后,在调用函数时不要使用位置参数,而只使用要更新的属性的关键字参数来调用它:

def set_warn_settings(serverID, **kwargs):
    with INSERTION_LOCK:
        try:
            row = SESSION.query(WarnSettings).get(serverID)
            if row:
                for k, v in kwargs.items():
                    setattr(row, k, v)
                # i removed SESSION.add(row) from here as you don't need to 
                # re-add an instance that was retrieved via Session.query.
                SESSION.commit()
            else:
                action = WarnSettings(**kwargs)
                SESSION.add(action)
                SESSION.commit()
        finally:
            SESSION.close()

如果行存在,这将只更新作为关键字参数传递给函数的属性名的值;如果行不存在,则将使用传入的值创建一个新的WarnSettings实例。它也不会覆盖您不想设置为None的属性值,但也允许您在需要时显式地将值设置为None。你知道吗

基于示例数据的用法示例:

set_warn_settings(102, behavior='action2')  # will change value of 'behavior' and not change 'limit'.
set_warn_settings(103, behavior='action1', limit=10)  # will change both fields
set_warn_settings(104, behavior='action3', limit=3)  # will create a new instance

注意,我还在函数中使用了^{}方法,这是一种按主键进行查询并在不存在行时返回None的简洁方法。你知道吗

所以这取决于您的需求是什么…但是您应该在设置之前检查behaviorlimit的值:

if behavior is not None:
    row.behavior = behavior
if limit is not None:
    row.limit = limit

但是,您可能会认为有时您希望能够将这些字段设置为None。在这种情况下,默认情况下可以将参数设置为特定对象。示例:

no_value = object()
def set_warn_settings(serverID, behavior=no_value, limit=no_value):

    ...
    if behavior is not no_value:
        row.behavior = behavior
    if limit is not no_value: 
        row.limit = limit
    ...

相关问题 更多 >