【问题标题】:How to use SQLite's UPSERT (or ON CONFLICT) with flask_sqlalchemy?如何将 SQLite 的 UPSERT(或 ON CONFLICT)与 flask_sqlalchemy 一起使用?
【发布时间】:2021-03-02 04:15:49
【问题描述】:

我想用外部 API 提供的数据更新我的 SQLite 数据库,我不想每次都自己检查是否有任何冲突,相反,我想利用 UPSERT 语句。 1.4 版的 SQLAlchemy 文档(仍处于测试阶段,但没关系)显示 this is possible。但我不知道如何让它与 flask_sqlalchemy 一起使用。

我还尝试将 sqlite_on_conflict='IGNORE' 包含在约束定义中(如 SQLAlchemy 文档 1.3 版 here 中所述):

class SomeModel(db.Model):
    __table_args__ = (
        db.ForeignKeyConstraint(
            ('id', 'other_id'),
            ('other_table.id', 'other_table.other_id')
            sqlite_on_conflict='IGNORE'
        ),
    )
    # ...

然后我验证了将SQLALCHEMY_ECHO 设置为True 的SQL 输出,但它根本不起作用...

我尝试了 1.3 和 1.4 SQLAlchemy 版本。

【问题讨论】:

  • 引用 sqlite 文档:“ON CONFLICT 子句适用于 UNIQUE、NOT NULL、CHECK 和 PRIMARY KEY 约束。ON CONFLICT 算法不适用于 FOREIGN KEY 约束。”。这让我相信问题不在于 sqlalchemy,而是 sqlite 不支持您想要的功能。你能用 UniqueConstraint 试试吗?
  • 我应该提到那些外键也是主键,但无论如何,我已经设法解决了这个问题

标签: python sqlite sqlalchemy flask-sqlalchemy


【解决方案1】:

感谢this gist(感谢droustchev)我找到了解决方案,我稍微edited。这有点乱,但它有效:

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql import Insert


@compiles(Insert, 'sqlite')
def suffix_insert(insert, compiler, **kwargs):
    stmt = compiler.visit_insert(insert, **kwargs)
    if insert.dialect_kwargs.get('sqlite_on_conflict_do_nothing'):
        stmt += ' ON CONFLICT DO NOTHING'
    return stmt


Insert.argument_for('sqlite', 'on_conflict_do_nothing', False)

只需将此代码包含在您的 models.py 文件(或您拥有的任何文件名)中,然后您就可以编写:

some_random_values = [
  {'id': 1, 'some_column': 'asadsadad'},
  {'id': 2, 'some_column': 'dsawaefds'}
]

stmt = db.insert(MyModel, sqlite_on_conflict_do_nothing=True).values(some_random_values)
db.session.execute(stmt)

这应该可以解决问题。

【讨论】:

    猜你喜欢
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 2020-06-02
    • 2016-07-21
    • 2022-12-04
    • 2017-01-27
    • 2016-08-07
    相关资源
    最近更新 更多