2013-08-28 78 views
1

這似乎是一件簡單的事情,但我似乎無法弄清楚如何;重新使用sqlalchemy ORM對象插入多條記錄

我在我的項目中有一個存儲金融交易的交易日誌表。在大多數情況下,我必須連續編寫一些這些事務,它們都共享很多屬性。

所以我想要做的是實例化一個Transactionlog對象,填寫常用屬性,然後不斷向會話中添加此原始對象的副本。

我當前的代碼是這樣的(簡化的,這是一個較大的類方法的一部分):

t = Transactionlog() 
    t.tlog_newData = origin 
    t.tlog_ppl_id = self._contract.member.ppl_id 
    t.tlog_datetime = period.period_start 
    t.tlog_shift_datetime = period.period_end 
    t.tlog_artc_id = revenue_article_id 
    t.tlog_club_id = self._contract.member.ppl_club_id 
    t.tlog_ppl_mshp_id = self._contract.ppl_mshp_id 


    periodlabel = "{0} to {1}".format(period.period_start, period.period_end) 

    # linked periodical articles AB 
    for linkedarticle in self._contract.linkedarticles: 
     if linkedarticle.pmar_periodical: 
      if linkedarticle.pmar_free: 
       t.price = 0 
      else: 
       t.price = linkedarticle.article.artc_price 
      t.tlog_artc_id = linkedarticle.artc_id 
      t.tlog_comment = "{0}: {1}".format(periodlabel, linkedarticle.article.artc_description) 
      t.tlog_evtt_id = 'ab' 
      t.tlog_code = 'member_linked_article' 
      db_session.add(t) 
      # counterbook SIS 
      t2 = t 
      t2.tlog_evtt_id = 'sis' 
      t2.price = t.price * -1 
      t2.link(t) 
      db_session.add(t2) 
      t.tlog_code = None 

    db_session.commit() 

你看到的就是初始對象噸的實例化。在鏈接的文章下,我循環了一堆文章並(嘗試)爲每篇文章預訂了一個新的AB類型的交易日誌行。每個預訂還有一個櫃檯預訂SIS。

在數據庫中我看到三條記錄出現,但都具有相同的屬性,它們都有tlog_evtt_id'sis',並且都有價格-1。所以它們似乎都獲得了最近設置的屬性。

我覺得添加到SQLAlchemy會話將生成一個INSERT與當前數據,然後編輯現有對象並再次添加它將生成第二個INSERT與新數據。

所以簡而言之,什麼是SQLAlchemy的方式將現有對象的副本插入到數據庫中?

回答

1

根據this answer你想有一個拷貝構造函數:

class Transactionlog(Base): 
    ... 
    @classmethod 
    def copy(cls, t): 
     t_new = cls() 
     t_new.tlog_newData = t.tlog_newData 
     ... 

另一個想法,你可以用與的functools.partial幫助。我的例子假定您有默認的SQLAlchemy的構造函數:

data = {'tlog_newData': origin, 
     'tlog_ppl_id': self._contract.member.ppl_id, 
     ... 
     } 
make_log = functools.partial(Transactionlog, **data) 

# linked periodical articles AB 
for linkedarticle in self._contract.linkedarticles: 
    if linkedarticle.pmar_periodical: 
     t = make_log() 
     ... 

我會說這實際上是乾淨方式,因爲它真的會創建一個新實例,每個對象要添加的 - 這就是你想要什麼。是的,有開銷,但稍後從數據庫中檢索這些對象時也會有開銷:這就是使用ORM的代價。

+0

謝謝,javex,我看過這個論壇帖子,但給出的解決方案是解決SQLalchemy。也是5歲,我認爲這是一個常見問題,SQLAlchemy將爲此實現一個解決方案。在接受解決方法是唯一的解決方案之前,我想等待其他人加入。 –

+0

我認爲這裏的問題是,它不是一個SQLAlchemy的問題,因爲它本身只做有意義的事情:通過它們的身份標識對象,即實例明智的。我在我的帖子中增加了另一個想法,也可以使用。 – javex

+0

我想我可能有一個解決方案:http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#sqlalchemy.orm.session.make_transient 我要測試和更新這個問題。 –

0

在類似的情況下,make_transient解決方案實際上適用於我,但它的行爲與它的記錄方式有點不同。

文檔states:「這將刪除它與任何會話的關聯,並另外刪除它的」標識關鍵字「,這樣就好像該對象是新構建的,除了保留其值。」

確實,對象被分離,但主鍵未被重置。 得到它的工作我不得不自己用這樣的方法進行清潔:

def cloneAndDetach (self): 
    session.make_transient(self) 
    self.id = None 
    return self 

也請注意scoped_session已經不是make_transient方法,讓您真正需要使用一個會話實例。