Reputation: 658
I have a working code of upserting several records by sqlalchemy
:
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy import BigInteger
from flask_sqlalchemy import SQLAlchemy as db
class PetModel(db.Model):
__tablename__ = "pets"
id = db.Column(BigInteger, primary_key=True)
data = db.Column(db.String(64), nullable=False, unique=True)
def as_dict(self):
return {
"id": getattr(self, "id"),
"data": getattr(self, "data"),
}
pets = [PetModel(id=1, data="Dog"), PetModel(id=2, data="Cat")]
insert_statement = insert(PetModel).values([_.as_dict() for _ in pets])
upsert_statement = insert_statement.on_conflict_do_update(
constraint="pet_pkey",
set_={"data": insert_statement.excluded.data},
)
ans = db.session.execute(upsert_statement)
I have tried to return all rows by adding returning(PetModel.__table__)
into insert_statement
, but I can't separate the answer of the [_ for _ in ans]
statement on updated and inserted. I don't want to add special field to database.
I know that ans.rowcount
returns the sum of updated and inserted records.
How could I get separately the amount of updated and inserted records using sqlalchemy
?
Upvotes: 0
Views: 1108
Reputation: 658
As Ilja Everilä
said, one of the decisions is to use the xmax
hack.
A column with this value we should add to the answer like describing here
from sqlalchemy.dialects.postgresql import insert
...
insert_statement = insert(PetModel).returning(
sqlalchemy.column("xmax") == 0
).values([_.as_dict() for _ in pets])
upsert_statement = insert_statement.on_conflict_do_update(
constraint="pet_pkey",
set_={"data": insert_statement.excluded.data},
)
ans = db.session.execute(upsert_statement)
created = sum([_._row[0] for _ in ans])
updated = len(pets) - created
Upvotes: 1