2017-01-13 120 views
2

INSERT語句中的PostgreSQL ON CONFLICT子句提供了「upsert」功能(即更新現有記錄,或者如果不存在此類記錄,則插入新記錄)。此功能在SQLAlchemy中通過PostgreSQL方言的Insert對象的on_conflict_do_nothingon_conflict_do_update方法(如描述here)支持:如何在flask_sqlalchemy中使用PostgreSQL的「INSERT ... ON CONFLICT」(UPSERT)功能?

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並創建我自己的會話?如果我這樣做,我怎麼能確保沒有衝突?

回答

1

事實證明,您可以在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請求過濾掉不需要的屬性。

相關問題