[英]How to increment a counter with upper limit in Django models, with a single query?
我有一個像這樣的Django模型:
class MyModel(models.Model):
upper_limit = models.PositiveIntegerField()
counter = models.PositiveIntegerField()
記錄的計數器需要經常增加:
mymodel = MyModel.objects.get(pk=123)
mymodel.counter = F('counter') + 1
mymodel.save()
問題是:在進行更新之前,我需要確保mymodel.counter小於mymodel.upper_limit。 我可以在更新之前進行查詢:
if mymodel.counter < mymodel.upper_limit:
mymodel.counter = F('counter') + 1
mymodel.save()
但是這種方法存在一些問題:計數器可能不准確。 查詢后其他線程可能已經更新了數據庫中的計數器,並且當我增加它時,該計數器將超過限制。 我知道我可以使用select_for_update()
鎖定行,但是我不想這樣做,因為那樣一來,所有增量操作都將被序列化,從而阻塞線程。
我想要的是僅在小於上限的情況下更新計數器,如下所示:
UPDATE MyModel set counter = counter + 1
where id=123 and counter<upper_limit
這對Django ORM可行嗎?
我一直在考慮pre_save信號,但是信號處理程序需要知道upper_limit,所以這是一個死胡同。
更新:怎么樣,這會生成一個SQL嗎?
updated_rows = MyModel.objects.filter(pk=123,
counter__lt=F("upper_limit")).update(counter=F("counter")+1)
# if updated_rows > 0, I know the counter is incremented
我不確定上面的語句是否會讓我得到單個查詢,因為update方法返回的是int而不是queryset,所以我無法打印其query
。
您需要在數據庫級別保持一致,因此任何應用程序側方法都無法確保這一點。 您需要的是數據庫內部的邏輯。 您可以在Django> = 1.8中使用觸發器或條件更新來實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.