首页 > 解决方案 > SQLalchemy 在提交之前避免在 session() 中重复

问题描述

尝试使用 session.merge() 使用 SQLalchemy 提交行时,出现重复错误。

我认为这是因为我获取数据的数据库允许列“哈希”的重复,而新的则不允许。

在提交之前,是否有一种简单的方法可以避免或删除当前会话中的重复项?

这是一个例子:

    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    from sqlalchemy.ext.automap import automap_base
    from src.python.utils import _gen_relationship

    engine = create_engine('mysql+pymysql://{user}:{pssw}@{host}/{db}?charset=utf8'.
                               format(user=config['user'],
                                      pssw=config['password'],
                                      host=config['host'],
                                      db=config['database'])
                               )

    database = [
        {'c_hash': 'd182jd012jd102jd1', 'date': '2017-01-01', 'text': 'oijwdqoijwdqoiqwdm'},
        {'c_hash': 'apiowjdaowndoaiwjda', 'date': '2017-01-01', 'text': 'oijwdqoijwdqoiqwdm'},
        {'c_hash': 'd182jd012jd102jd1', 'date': '2017-01-02', 'text': 'adawdawdawd'}
    ]

    Base = automap_base()
    Base.prepare(engine, reflect=True, generate_relationship=_gen_relationship)

    # load necessary table information
    Mytable = Base.classes.mytable

    Session = sessionmaker(bind=engine, autoflush=False)
    session = Session()

    for row in database:
        new_row = {
            'hash': row['c_hash'],
            'date': row['date'],
            'text': row['text']
        }

        session.merge(Mytable(**new_row))
    session.commit()

谢谢

标签: pythonmysqlsqlalchemy

解决方案


看起来你最好在你的应用程序中“去重”:

seen = set()

# Reversed so that the last row wins.
for row in reversed(database):
    c_hash = row['c_hash']
    if c_hash not in seen:
        session.merge(Mytable(hash=c_hash,
                              date=row['date'],
                              text=row['text']))
        seen.add(c_hash)

理论上,您也可以让 SQLAlchemy 处理重复数据删除:

for row in database:
    session.merge(Mytable(hash=row['c_hash'],
                          date=row['date'],
                          text=row['text']))
    session.flush()

诀窍是在两者之间刷新,以便以后的合并将咨询数据库并找到现有行,但与其他解决方案相比,这将执行更多查询。


推荐阅读