如何在不更改未指定列的情况下更新SQLAlchemy行的某些列?

时间:2018-07-29 05:38:22

标签: python python-3.x sqlalchemy

我有一个包含3行的表格,如下所示:

| 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以外的参数来调用该函数。

如何通过一个功能来更新某一列的值,而其余部分保持不变?

2 个答案:

答案 0 :(得分:0)

所以这取决于您的要求...但是在设置之前,您应该检查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
    ...

答案 1 :(得分:0)

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

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

请注意,我还在函数中使用了.get()方法,这是一种通过主键查询并在行不存在时返回None的巧妙方法。