【问题标题】:How to Use Django Queryset update() function with foreign key field cited by F()?如何使用带有 F() 引用的外键字段的 Django Queryset update() 函数?
【发布时间】:2021-10-20 19:53:02
【问题描述】:

我想做一个简单的查询:

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 子句进行 FOR UPDATE”

子查询不起作用,因为聚合不适用于 select_for_update() 锁。 F() 不起作用,因为它引用了外键字段...

使这个查询工作的最佳方法是什么?有什么想法吗?

  • 我在 ORM 后面使用 postgresql。

【问题讨论】:

    标签: django postgresql django-models django-orm


    【解决方案1】:

    我是这样做的:

    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 引用外键字段可以通过子查询来解决。但是你不能聚合被 select_for_update() 锁定的行。

    我选择依赖无法从客户端从 timezone.now()-timedelta(days=14) 修改的“payments_due_payout”,然后我获取 Payment created_date__lt=timezone.now()-timedelta( days=15), 相差一天。我认为任何对 payment_due_payout 的并发请求都不会在 Django 服务器上持续 1 天。

    所以应该没有问题,但在理想情况下,我们应该完全防止status='PENDING'的数据更改的可能性,以编程方式。

    如果你有更好的想法,请告诉我。

    【讨论】:

      猜你喜欢
      • 2012-11-14
      • 2011-01-30
      • 2018-02-15
      • 2021-06-13
      • 2015-11-11
      • 2021-12-09
      • 2019-03-25
      • 1970-01-01
      • 2013-11-04
      相关资源
      最近更新 更多