1

这似乎很简单,但我似乎不知道怎么做;

我的项目中有一个事务日志表,用于存储金融交易。在大多数情况下,我必须连续编写许多此类事务,它们都共享许多属性。

所以我想做的是实例化一个 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()

你看到的是初始对象 t 的实例化。在链接的文章下,我循环浏览一堆文章并(尝试)为每篇文章预订一个新的事务日志行,类型为 AB。每个预订也有一个柜台预订SIS。

在数据库中,我确实看到了三个记录,但它们都具有相同的属性,它们都具有 tlog_evtt_id 'sis' 并且都具有价格 -1。因此,它们似乎都获得了最近设置的属性。

我认为添加到 SQLAlchemy 会话会生成一个包含当前数据的 INSERT,然后编辑现有对象并再次添加它会生成一个包含新数据的第二个 INSERT。

简而言之,将现有对象的副本插入数据库的 SQLAlchemy 方法是什么?

4

2 回答 2

1

根据这个答案,您需要一个复制构造函数:

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 的代价。

于 2013-08-28T08:26:14.830 回答
0

make_transient 解决方案实际上在类似情况下对我有用,但它的行为与记录的方式略有不同。

文档指出:“这将删除它与任何会话的关联,另外还会删除它的“身份密钥”,这样就好像对象是新构建的,除了保留它的值。

确实,对象被分离了,但是主键没有被重置。为了让它工作,我必须自己用这样的方法清理它:

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

另请注意, scoped_session 没有 make_transient 方法,因此您确实需要使用会话实例。

于 2015-09-09T20:53:56.967 回答