Sqlalchemy的merge上的psycopg2.errors.UniqueViolation

问题描述

我有一个带有复合主键的模型 我正在尝试使用sqlalchemy的merge()方法执行upsert。 出于某种原因,它在我的其他测试模型(复合键总共由7个cols组成)上运行良好,但是在此测试模型上却很难进行

class Offsets(db.Model,CommonMethods):
    symbol_id = db.Column(db.String(120),primary_key=True)
    account_id = db.Column(db.String(120),primary_key=True)
    settlement_counterparty = db.Column(db.String(120),primary_key=True)
    execution_counterparty = db.Column(db.String(120),primary_key=True)
    counterparty_account_id = db.Column(db.String(120))
    Trade_date = db.Column(db.String(10),primary_key=True)

    daily_diff = db.Column(db.String(120))
    buy_qty = db.Column(db.String(120))
    sell_qty = db.Column(db.String(120))
    pos_before_Trade = db.Column(db.String(120))
    pos_after_Trade = db.Column(db.String(120))
    
    
    offset =  db.Column(db.String(120))#resulting offset

    related_orders = db.Column(db.ARRAY(db.String(360)))

    comment = db.Column(db.String(360))

    manual = db.Column(db.Boolean,default=False,primary_key=True)
    settlement = db.Column(db.Boolean,primary_key=True) #for some reason if i remove this from model,merging goes fine

在我尝试执行upsert以下

app=create_app()
app.app_context().push()

entry=Offsets(
        Trade_date='2020-09-29',symbol_id='AAPL',account_id='FOO',buy_qty='0',settlement_counterparty='BAR',execution_counterparty='BAZ',counterparty_account_id='FOOBARBAZ',sell_qty='1',daily_diff='1',related_orders=['some_uuids_here'],manual=False
    )

db.session.merge(entry)
<Offsets (transient 140184049284712)>
db.session.commit()#first went fine as it wasnt in db
None
db.session.merge(entry)
<Offsets (transient 140184049535072)>
db.session.commit()#second time it returns an error though
Traceback (most recent call last):
  File "<string>",line 1,in <module>
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/scoping.py",line 162,in do
    return getattr(self.registry(),name)(*args,**kwargs)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/session.py",line 1027,in commit
    self.transaction.commit()
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/session.py",line 492,in commit
    self._assert_active(prepared_ok=True)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/session.py",line 295,in _assert_active
    code="7s2a",sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a prevIoUs exception during flush. To begin a new transaction with this Session,first issue Session.rollback(). Original exception was: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "offsets_pkey"
DETAIL:  Key (symbol_id,account_id,settlement_counterparty,execution_counterparty,Trade_date,manual,settlement)=(AAPL,FOO,BAR,BAZ,2020-09-29,f,f) already exists.

上面的代码不应该执行upsert(在冲突时更新非主键列)吗?

解决方法

由于某种原因,settlement = False在模型中entry不够,我在创建default=False时必须明确定义admin-new-order.php