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

时间:2022-12-19 19:15:41

My Django app has a User model, those Users have many Transactions. Some of my views display a summary (summation) of all transaction amounts, let's call it the 'total'. So far, this has been tallied up when needed for display.

我的Django应用程序有一个用户模型,这些用户有很多事务。我的一些视图显示了所有交易金额的汇总(汇总),我们称之为“总计”。到目前为止,当需要显示时,已经对其进行了统计。

Now, I'd like to add this tally to essentially every page a User views... so I'd prefer it to come from a DB/model field, that's maintained with each new Transaction. I know how to do that: add a 'total' field to my User model, update it as needed (using the Django ORM F()-expressions for race-proof-ness). So far so good.

现在,我想把这个数字添加到每个用户浏览的页面中……因此,我希望它来自DB/model字段,这是每个新事务维护的。我知道如何做到这一点:在我的用户模型中添加一个“total”字段,并根据需要更新它(使用Django ORM F()-表达式来进行race-proof-ness)。目前为止一切都很顺利。

My question regards setting the initial 'total' value, tracking all Transactions so far (before the running-tally was implemented).

我的问题是关于设置初始的“total”值,跟踪到目前为止的所有事务(在执行记录之前)。

I suppose I could, during a maintenance window where no new Transactions arrive, do a data-migration initializing all User.total values to the current tally. However, I'd rather not do that: the last similar big data-migration I did took hours longer than expected.

我想,在没有新事务到达的维护窗口中,我可以对所有用户进行数据迁移初始化。对当前统计值的总值。然而,我宁愿不这么做:我所做的上一次类似的大数据迁移比预期的要长几个小时。

Is there a recommended technique/trick for doing the catchup tallying without a long outage, while new transactions are also arriving?

是否有一种推荐的技术/技巧,可以在不长时间中断的情况下进行跟踪计数,同时也会出现新的事务?

I suppose I could write the catchup data-migration to consider only transactions before the threshold date (or id) at the moment the new, tally-maintaining code is deployed. (Then, I'd run the data-migration while the system is up, and only reveal the new tallies in the interface when the migration completes, no matter how long that takes.) However, I'd rather not code this date/id threshold into the migration source code. Is there South metadata that could be used for this purpose?

我认为我可以编写追赶数据迁移,只考虑在部署新的、维护数据的代码时阈值日期(或id)之前的事务。(然后,当系统启动时,我将运行数据迁移,只在迁移完成时显示新数据,不管需要多长时间。)但是,我不希望将这个日期/id阈值编码到迁移源代码中。是否有可以用于此目的的南方元数据?

1 个解决方案

#1


2  

I'm afraid there is no "one size fits all" solution to the problem you described.

恐怕没有“一刀切”的办法来解决你所描述的问题。

It seems to me that you have a good understanding of what should be done, so let me suggest one other possible solution.

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

Assuming that you have a large number of users and each user has a small or moderate amount of transactions (so that processing a single user's transactions doesn't take ages), you could do something like this in your South data migration (using the old Django transactions as you asked the question before Django 1.6 was out):

假设您有大量的用户,每个用户都有一个小或中等数量的事务(这样处理一个用户的交易不需要年龄的),你会做这样的事情在南数据迁移(使用旧的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()

Then you could add the following method to your User model:

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

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

And the transaction creation code could look like this:

事务创建代码如下所示:

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()

You could even get rid of the transactions_migrated field and replace it with some _total is None check.

您甚至可以删除transactions_迁移字段,并使用一些_total替换它,这是没有检查的。

#1


2  

I'm afraid there is no "one size fits all" solution to the problem you described.

恐怕没有“一刀切”的办法来解决你所描述的问题。

It seems to me that you have a good understanding of what should be done, so let me suggest one other possible solution.

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

Assuming that you have a large number of users and each user has a small or moderate amount of transactions (so that processing a single user's transactions doesn't take ages), you could do something like this in your South data migration (using the old Django transactions as you asked the question before Django 1.6 was out):

假设您有大量的用户,每个用户都有一个小或中等数量的事务(这样处理一个用户的交易不需要年龄的),你会做这样的事情在南数据迁移(使用旧的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()

Then you could add the following method to your User model:

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

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

And the transaction creation code could look like this:

事务创建代码如下所示:

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()

You could even get rid of the transactions_migrated field and replace it with some _total is None check.

您甚至可以删除transactions_迁移字段,并使用一些_total替换它,这是没有检查的。