Consider two models:
AutoField
primary key PositiveIntegerField
AutoField
primary key PositiveIntegerField
ForeignKey
to Project
For each project, I wish to ensure that the sum of their expenses is less than or equal to the budget at all times.
In SQL terms: SELECT SUM(amount) FROM expense WHERE project_id = ?;
should always be less than or equal SELECT budget FROM project WHERE id = ?;
Is there any way to do this in Django, keeping in mind that multiple people may be accessing the web server and creating Expense
s at the same time?
I am using postgresql as my database backend.
I have tried using select_for_update
but that doesn't prevent INSERT
s from taking place and it doesn't seem to work on aggregations anyway.
I was considering save
ing the Expense
to the database first, then query the total cost and remove the Expense
if it's over-budget but then I would need that code to be outside of a transaction so that other threads can see it and then if the server stops mid-processing, the data could be left in an invalid state.
Thanks to @Alasdair for pointing me in the right direction.
After filling out the fields of inst
(a new Expense
), do:
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()
Note that I have total_cost
defined as a method on Project
:
class Project:
def total_cost(self):
return self.expense_set.all().aggregate(
t=Sum(F('cost')))['t']
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.