2017-01-13 2 views
2

INSERT에있는 PostgreSQL ON CONFLICT 절은 "upsert"기능을 제공합니다 (즉, 기존 레코드를 업데이트하거나 그러한 레코드가없는 경우 새 레코드를 삽입합니다). 이 기능은 (설명 here 등) PostgreSQL의 방언의 Insert 객체에 on_conflict_do_nothingon_conflict_do_update 방법을 통해 SQLAlchemy의 지원됩니다 : 당신을 위해 SQLAlchemy의의 엔진, 세션 및 연결을 관리 flask_sqlalchemy을 사용하고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) 

.

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에 의해 가려 : 데이터베이스에 요소를 추가하려면, 나는 이런 식으로 뭔가를 내 모델의 인스턴스를 생성 데이터베이스 세션에 추가하고 커밋 전화 .

Upsert를 수행하기 위해 PostgreSQL 관련 dialect 메서드에 액세스하려면 어떻게해야합니까? 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 요청에서 원하지 않는 속성을 필터링하는 생성자를 사용할 수 있도록 : 그래서 해결책은 다음과 같이 보인다.

관련 문제