将 Django/South/PostgreSQL 从按需要计算的汇总值迁移到数据库中维护的汇总值的正确方法是啥?
Posted
技术标签:
【中文标题】将 Django/South/PostgreSQL 从按需要计算的汇总值迁移到数据库中维护的汇总值的正确方法是啥?【英文标题】:What's the right way to do a Django/South/PostgreSQL migration from calculated-as-needed summary values to maintained-in-database summary values?将 Django/South/PostgreSQL 从按需要计算的汇总值迁移到数据库中维护的汇总值的正确方法是什么? 【发布时间】:2013-04-23 10:38:27 【问题描述】:我的 Django 应用程序有一个用户模型,这些用户有很多事务。我的一些观点显示了所有交易金额的汇总(总和),我们称之为“总计”。到目前为止,这已经在需要显示时进行了统计。
现在,我想将这个计数添加到用户查看的每个页面中......所以我希望它来自数据库/模型字段,每个新事务都会维护它。我知道如何做到这一点:在我的用户模型中添加一个“总计”字段,根据需要更新它(使用 Django ORM F()-expressions for race-proof-ness)。到目前为止,一切都很好。
我的问题是关于设置初始“总”值,跟踪到目前为止的所有交易(在运行统计实施之前)。
我想我可以在没有新事务到达的维护窗口期间进行数据迁移,将所有 User.total 值初始化为当前计数。但是,我宁愿不这样做:我所做的最后一次类似的大数据迁移花费的时间比预期的要长。
是否有推荐的技术/技巧可以在没有长时间中断的情况下进行追赶统计,同时新的交易也即将到来?
我想我可以编写追赶数据迁移,以便在部署新的计数维护代码时仅考虑阈值日期(或 ID)之前的事务。 (然后,我会在系统启动时运行数据迁移,并且只在迁移完成时在界面中显示新的计数,无论需要多长时间。)但是,我宁愿不编码这个日期/ id 阈值进入迁移源代码。是否有可用于此目的的 South 元数据?
【问题讨论】:
【参考方案1】:恐怕您所描述的问题没有“一刀切”的解决方案。
在我看来,您对应该做什么很了解,所以让我建议另一种可能的解决方案。
假设您有大量用户并且每个用户都有少量或中等数量的交易(这样处理单个用户的交易不会花费很长时间),您可以在 South 数据迁移中执行类似的操作 (在 Django 1.6 发布之前使用旧的 Django 事务):
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
检查。
【讨论】:
以上是关于将 Django/South/PostgreSQL 从按需要计算的汇总值迁移到数据库中维护的汇总值的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Javascript 将正则表达式 \\n 替换为 \n,将 \\t 替换为 \t,将 \\r 替换为 \r 等等