簡體   English   中英

如何通過單個查詢在Django模型中增加具有上限的計數器?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM