我想做一个简单的查询:
with transaction.atomic():
Account.objects.select_for_update().filter(payments__status='PENDING', payments__created_date__lt=timezone.now()-timedelta(days=14)).update(balance=F('balance')+Sum(F('payments__amount') - F('payments__payment_fee__fee_amount')), payments__status='COMPLETED')
结果一点也不简单。我已经尝试了子查询,但是在此查询中不允许获得"连接字段引用"。
不允许使用GROUP BY子句">子查询不能工作,因为聚合不能与select_for_update()锁一起工作。F()不能工作,因为它引用了外键字段…
使这个查询工作的最好方法是什么?任何想法?
- 我在ORM后面使用postgresql。
我是这样做的:
with transaction.atomic():
payments_due_payout = models.Payment.objects.filter(status='PENDING', created_date__lt=timezone.now()-timedelta(days=15))
total_payout = Subquery(models.Account.objects.filter(payments__in=payments_due_payout, id=OuterRef('id')).annotate(total_payout=Sum(F('payments__amount') - F('payments__payment_fee__fee_amount'))).values('total_payout')[:1])
models.Account.objects.select_for_update().filter(payments__in=payments_due_payout).update(balance=F('balance')+total_payout)
payments_due_payout.update(status='COMPLETED')
在update()函数中用F引用外键字段可以用Subquery解决。但是你不能聚合被select_for_update()锁定的行。
我选择依靠"payments_due_payout"这是不可能从客户端修改timezone.now()-timedelta(days=14),我获取支付create_date_lt =timezone.now()-timedelta(days=15),这是一天的差异。我不认为任何对payments_due_payments的并发请求会在Django服务器上持续一天。
所以应该没有问题,但是在理想情况下,我们应该完全防止通过编程方式更改status='PENDING'的数据的可能性。
如果你有更好的主意,请告诉我。