从计算所需的汇总值到维护数据库汇总值进行Django / South / PostgreSQL迁移的正确方法是什么?

时间:2013-04-29 16:56:10

标签: django django-south django-orm django-postgresql

我的Django应用程序有一个用户模型,那些用户有很多交易。我的一些观点显示了所有交易金额的摘要(总和),我们将其称为“总计”。到目前为止,在显示需要时已经计算好了。

现在,我想将这个标记添加到用户查看的每个页面......所以我更喜欢它来自DB /模型字段,这是用每个新事务维护的。我知道如何做到这一点:在我的User模型中添加一个'total'字段,根据需要更新它(使用Django ORM F() - race-proof-ness的表达式)。到现在为止还挺好。

我的问题是设置初始'总'值,跟踪到目前为止的所有事务(在执行运行计数之前)。

我想我可以在没有新事务到达的维护窗口中进行数据迁移,将所有User.total值初始化为当前计数。但是,我宁愿不这样做:我所做的最后一次类似的大数据迁移花费的时间比预期的要长几个小时。

是否有推荐的技巧/技巧可以在没有长时间停机的情况下进行追赶计数,而新的交易也会到达?

我想我可以编写catchup数据迁移,以便在部署新的计数维护代码时仅考虑阈值日期(或id)之前的事务。 (然后,我会在系统启动时运行数据迁移,并且只有在迁移完成时才会显示界面中的新标签,无论需要多长时间。)但是,我宁愿不编码此日期/ id阈值进入迁移源代码。南方元数据是否可以用于此目的?

1 个答案:

答案 0 :(得分:2)

我担心你所描述的问题没有“一刀切”的解决方案。

在我看来,你对应该做什么有很好的理解,所以让我建议另一个可能的解决方案。

假设您拥有大量用户且每个用户都有少量或中等数量的交易(因此处理单个用户的交易时间不长),您可以在南方数据迁移中执行类似的操作(使用旧的Django事务,因为你在Django 1.6出局之前提出了问题):

from django.db import transaction
for user in orm.User.objects.all():
    with transaction.commit_on_success():
        user._total = calculate_sum_of_transactions_for_user(user)
        user.transactions_migrated = True
        user.save()

然后,您可以将以下方法添加到您的用户模型中:

@property
def total(self):
    if self.transactions_migrated:
        return self._total
    else:
        return calculate_sum_of_transactions_for_user(user)

交易创建代码可能如下所示:

class Transaction(models.Model):
    amount = models.DecimalField(...)

    def save(self, ...):
        super().save(...)
        if self.user.transactions_migrated:
            self.user._total = F('_total') + self.amount
            self.user.save()

您甚至可以删除transactions_migrated字段,并将其替换为_total is None次检查。