SQLAlchemy:仅当特定项目不存在时才插入

SQLAlquemy: INSERT only if specific item(s) dont exist

我一直在寻找一种仅在特定对象组合不存在时才创建对象的简单方法。

示例:我有这个 class。我的目标是仅在“事实”中的对象不相同时才插入一个新对象。

class Facts(Base):
    __tablename__ = "facts"

    id = sqlColumn(Integer, primary_key=True)
    fact = sqlColumn(String(500))
    created_at = sqlColumn(DateTime)
    updated_at = sqlColumn(DateTime)

我已经在 Does SQLAlchemy have an equivalent of Django's get_or_create?

找到了这段代码
def get_or_create(session, model, **kwargs):
    instance = session.query(model).filter_by(**kwargs).one_or_none()

    if instance:
        return instance
    else:
        instance = model(**kwargs)
        session.add(instance)
        return instance

但这并不能真正满足我的需要,因为无论如何都会创建对象,因为“创建于”的时间戳不同。

此外,我想添加尽可能多的过滤器元素。

您可以使用唯一约束使事实列在所有行中唯一,即。 unique=True。然后仅在创建时单独传递 datetime 列:


class Facts(Base):
    __tablename__ = "facts"

    id = sqlColumn(Integer, primary_key=True)
    # Makes sure there are no duplicate facts on the database level
    fact = sqlColumn(String(500), unique=True)
    created_at = sqlColumn(DateTime)
    updated_at = sqlColumn(DateTime)

def get_or_create(session, model, created_at, **unique_kwargs):
    instance = session.query(model).filter_by(**unique_kwargs).one_or_none()

    if instance:
        return instance
    else:
        instance = model(created_at=created_at, updated_at=created_at, **unique_kwargs)
    session.add(instance)
    return instance

你可以这样使用:

result = get_or_create(session, Facts, datetime.now(), fact='A new fact')

这种方法的缺点是使用不同会话的一个线程可能会在同一时间创建一个事实,而另一个线程正在创建同一线程并且代码将在提交时失败。数据库的完整性将通过约束得以保留。您可以通过捕获完整性异常并再次尝试 get_or_create 来解决这个问题。如果你使用的是 postgresql,你应该做一个 upsert,解释如下:Upsert Documentation

这是创建唯一约束的 SQLAlchemy 文档: Unique Constraints