如何在flask_sqlalchemy中使用PostgreSQL的“INSERT … ON CONFLICT”(UPSERT)功能?

INSERT语句中的Postgresql ON CONFLICT子句提供“upsert”功能(即更新现有记录,或者如果不存在此类记录则插入新记录). sqlAlchemy通过Postgresql方言的Insert对象上的on_conflict_do_nothing和on_conflict_do_update方法支持功能(如here所述):

from sqlalchemy.dialects.postgresql import insert

insert_stmt = insert(my_table).values(
    id='some_existing_id',data='inserted value'
)

do_nothing_stmt = insert_stmt.on_conflict_do_nothing(
    index_elements=['id']
)

conn.execute(do_nothing_stmt)

do_update_stmt = insert_stmt.on_conflict_do_update(
    constraint='pk_my_table',set_=dict(data='updated value')
)

conn.execute(do_update_stmt)

我正在使用flask_sqlalchemy,它管理sqlAlchemy的引擎,会话和连接.要向数据库添加元素,我创建模型的实例,将其添加数据库会话,然后调用commit,如下所示:

from flask import Flask
from flask_sqlalchemy import sqlAlchemy

app = Flask(__name__)
db = sqlAlchemy(app)

class MyTable(db.Model):
    id = db.Column(UUID,primary_key=True)
    data = db.Column(db.String)

relation = MyTable(id=1,data='foo')
db.session.add(relation)
db.session.commit()

所以Insert对象被flask_sqlalchemy完全包装和遮盖.

如何访问Postgresql特定的方言方法来执行upsert?我是否需要绕过flask_sqlalchemy并创建自己的会话?如果我这样做,我怎么能确保没有冲突?

最佳答案
事实证明,您可以在db.session上执行较低级别的语句.所以解决方案看起来像这样:

from flask import Flask
from flask_sqlalchemy import sqlAlchemy
from sqlalchemy.dialects.postgresql import insert as pg_insert

app = Flask(__name__)
db = sqlAlchemy(app)

class MyTable(db.Model):
    id = db.Column(UUID,primary_key=True)
    data = db.Column(db.String)

    def __init__(self,_id,*args,**kwargs):
        self.id = _id
        self.data = kwargs['data']

    def as_dict(self):
        return {'id': self.id,'data': self.data}

    def props_dict(self):
        d = self.as_dict()
        d.pop('id')
        return d

relation = MyTable(id=1,data='foo')
statement = pg_insert(MyTable)\.
    values(**relation.as_dict()).\
    on_conflict_do_update(constraint='id',set_=relation.props_dict())

db.session.execute(statement)
db.session.commit()

我的模型类中的as_dict()和props_dict()方法允许我使用构造函数从传入的HTTP请求中过滤掉不需要的属性.

相关文章

在这篇文章中,我们深入学习了XPath作为一种常见的网络爬虫技巧。XPath是一种用于定位和选择XML文档中特...
祝福大家龙年快乐!愿你们的生活像龙一样充满力量和勇气,愿你们在新的一年里,追逐梦想,勇往直前,不...
今天在爬虫实战中,除了正常爬取网页数据外,我们还添加了一个下载功能,主要任务是爬取小说并将其下载...
完美收官,本文是爬虫实战的最后一章了,所以尽管本文着重呈现爬虫实战,但其中有一大部分内容专注于数...
JSON是一种流行的数据传输格式,Python中有多种处理JSON的方式。官方的json库是最常用的,它提供了简单...
独立样本T检验适用于比较两组独立样本的均值差异,而配对T检验则适用于比较同一组样本在不同条件下的均...