2011-08-29 20 views
2

我是個新手的Django。我在Uni的網絡編程課程中做了一個粗略的計數器。我做了一個類HitCount:Django的頁面命中計數器併發

from django.db import models 

# Create your models here. 

class HitCount(models.Model): 
    count = models.IntegerField() 

然後我在意見文件中使用此代碼:

def index(request): 

    #try getting a hitcounter, if there is none, create one 
    try: 
     hc = HitCount.objects.get(pk=1) 
    except: 
     hc = HitCount(count=0) 
     hc.save() 
     pass 

    #get a queryset containing our counter 
    hc = HitCount.objects.filter(pk=1) 
    #increment its count and update it in db 
    hc.update(count=F('count')+1) 
    #ATM hc is a queryset, so hc.count will just return how many 
    #counters are in the queryset (1). So we have to get the 
    #actual counter object 
    hc = HitCount.objects.get(pk=1) 
    #and return its count 
    return render_to_response('hitcount/index.html', {'count': hc.count}) 

這是我的index.html文件:

<p>{{count}}</p> 

這似乎是工作蠻好的,但我想知道:

  • 這是一個合理的方式這樣做?增量的代碼是否應該真正駐留在視圖文件中?或者我應該將其轉化爲課堂中的一種方法?
  • 這是併發安全或是否需要使用某種類型的鎖?部分任務是使計數器併發安全。我使用SQLite,它使用事務,所以我認爲它應該是好的,但我可能會錯過一些東西。
+1

交易將不被自動使用。雖然它確實刪除了ORM的一些細節,但如果您使用的是MySQL,可以在一個查詢中完成:INSERT INTO hitcount(id,count)VALUES(1,1)ON DUPLICATE KEY UPDATE count = count + 1'。這避免了完全交易的需要。 (您可以在Oracle或SQL服務器中使用MERGE INTO,在PostgreS中使用UDF) –

+0

歡迎您的輸入。你介意擴大一點嗎?例如。如何強制使用交易?以及如何使用手動查詢消除對交易的需求?那麼不應該有兩個查詢同時執行的風險,導致錯誤? – fred

+1

查看[這裏](https://docs.djangoproject.com/en/dev/topics/db/transactions/#django-s-default-transaction-behavior),瞭解有關Django如何處理事務以及如何讓Django自動使用交易。至於我的備選建議,每個更新都是在單個語句中執行的,並且由數據庫服務器將其視爲原子,所以沒有事務。 –

回答

3

偏離主題,但您應該在try/catch中捕獲HitCount.DoesNotExist,因爲除非HitCount對象還不存在,否則您確實只想執行代碼。

如果有可能,你可能想看看像Redis(或其他鍵/ VAL店)做你的命中計數器。

Redis提供了一種名爲INCR的方法,該方法會自動將值增加1.它是超快速的,並且是像這樣的熱門計數器的絕佳解決方案。你所需要做的就是製作一個與頁面相關的關鍵字,你可以用+1來增加它。

它也可能使使用middleware類跟蹤頁面命中更有意義。比將其添加到每個視圖要容易得多。如果您需要在每個頁面上顯示此計數,則可以使用context processormore info)將頁面的命中數添加到上下文中。這種方式會減少重複代碼。

編輯

我最初錯過了,這是一個統一的項目,所以這可能是在大量工程爲你所需要的。但是,如果您要爲生產環境構建一個熱門計數器,這就是我的建議。您仍然可以使用中間件/上下文處理器以DRY方式執行命中計數/檢索。

+0

這是一個很好的答案和很好的信息!雖然Redis在這種特殊情況下可能略微有點過分,但我肯定會考慮將一些代碼移到中間件類中,這感覺就像是一個更好的設計。因爲您向我提供了可以解答我的兩個問題的信息,所以我會將其標記爲已接受的答案。 – fred

+0

感謝Fred,祝你的項目好運。 –

0

您可以爲每個命中創建一個新的數據庫行並調用HitCount.objects.count()來獲得計數。

+0

感謝您的貢獻,但可以說它只是簡單地增加了對象計數值,更加乾淨輕便。 – fred

2

鎖定使用以下是可能的蟒蛇:

lock = Lock() 
lock.acquire() 
try: 
    ... access shared resource 
finally: 
    lock.release() # release lock, no matter what 

請記住,方法是不是安全的多服務器環境雖然。

您還可以創建一個更可擴展的「記錄」的解決方案,跟蹤每個命中爲與相關信息的分貝行,然後可以算甚至在某個特定日期範圍/查詢。

+0

謝謝,我將在我的代碼中執行此操作! – fred