考虑两种模式:
AutoField
主键PositiveIntegerField
AutoField
主键PositiveIntegerField
ForeignKey
到Project
对于每个项目,我希望确保其费用总和始终小于或等于预算。
在SQL术语中:SELECT SUM(amount) FROM expense WHERE project_id = ?;
应始终小于或等于SELECT budget FROM project WHERE id = ?;
有没有办法在Django中执行此操作,请记住多人可能正在访问Web服务器并同时创建Expense
?
我使用postgresql作为我的数据库后端。
我尝试使用select_for_update
,但这并不妨碍INSERT
发生,而且无论如何它似乎都无法用于聚合。
我首先考虑save
将Expense
添加到数据库,然后查询总费用并删除Expense
,如果它超出预算但我需要该代码在事务之外,以便其他线程可以看到它,然后如果服务器停止处理中,则数据可能会处于无效状态。
答案 0 :(得分:1)
感谢@Alasdair指出我正确的方向。
填写inst
(新Expense
)字段后,执行:
with transaction.atomic():
project = models.Project.objects.select_for_update().get(
pk=project_id)
cost = project.total_cost()
budget = project.budget
if cost + inst.cost > budget:
raise forms.ValidationError(_('Over-budget'))
self._inst.save()
请注意,我已将total_cost
定义为Project
上的方法:
class Project:
def total_cost(self):
return self.expense_set.all().aggregate(
t=Sum(F('cost')))['t']