2010-11-19 53 views
1

我正在使用django-hitcount來達到我的數據庫對象。我想通過對象計算命中數來確定哪個對象在給定時間範圍內命中最多。該應用程序有興趣在這裏兩種型號:在Django中用一般關係註釋

class Hit(models.Model): 
    created   = models.DateTimeField(editable=False) 
    ip    = models.CharField(max_length=40, editable=False) 
    session   = models.CharField(max_length=40, editable=False) 
    user_agent  = models.CharField(max_length=255, editable=False) 
    user   = models.ForeignKey(User,null=True, editable=False) 
    hitcount  = models.ForeignKey(HitCount, editable=False) 

class HitCount(models.Model): 
    hits   = models.PositiveIntegerField(default=0) 
    modified  = models.DateTimeField(default=datetime.datetime.utcnow) 
    content_type = models.ForeignKey(ContentType, 
         verbose_name="content cype", 
         related_name="content_type_set_for_%(class)s",) 
    object_pk  = models.TextField('object ID') 
    content_object = generic.GenericForeignKey('content_type', 'object_pk') 

「命中」記錄每打一個時間戳,而HitCount店命中總數。要根據對象和時間範圍內獲得的點擊,我需要做到以下幾點:通過以上 回報計算次數

過濾器的日期點擊創建每content_object命中 計數次數(時間範圍內上述過濾) 秩序content_object和計數

這可能非常昂貴,所以我計劃每天進行一次調取/緩存。

作爲第一步,我想計算每個content_object的點擊次數,而不考慮時間範圍。

limited_hc = Hit.objects.all().values('hitcount__content_object').annotate(count = Count('hitcount__object_pk')) 

我立刻碰到一個問題:

無法解析關鍵字 'hitcount__content_object' 到現場。選擇是:創建,hitcount,id,ip,會話,用戶,user_agent

經過一番挖掘,我發現annotation and generic relations do not work well together。如果我使用object_pk而不是content_object,它可以正常工作,但是我沒有該對象的名稱。

所以我的問題:什麼是取得同樣結果的替代方法?如何可以按對象分組,但也保留名稱?

我確實有model(content_type)和id(object_pk),所以我總是可以單獨拉這些,但看起來不夠雅緻。 。 。

+0

現在沒有可能嘗試這種方式,但是您是否嘗試過'limited_hc = Hit.objects.all()。values('hitcount__content_type','hitcount__object_pk')。annotate(count = Count('hitcount__object_pk'))'? – 2010-11-19 11:57:32

+0

這有效,但我沒有得到實際對象的鏈接。所以我不能得到名字,只有PK。然後,我必須再次ping數據庫以從相應表中提取名稱數據。 – 2010-11-19 16:41:12

回答

1

它可能會更有效地爲你的目的的通用關係添加到Hit型號:

class Hit(models.Model): 
    ... 
    object_id = models.PositiveIntegerField() 
    content_type = models.ForeignKey(ContentType) 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

,然後運行計數()查詢上直接命中:

t = ContentType.objects.get_for_model(the_object_being_hit) 
id = the_object_being_hit.id 
count = Hit.objects.filter(
        created__range=(from_timestamp, to_timestamp), 
        content_type = t, 
        object_id = id 
       ).count() 

你可以使用Django South遷移系統修改命中數模型。你也可以在Monkey修補它的Meta類後嘗試子類化Hit,或者只是定義更適合你的需求的自己的模型。

編輯如果你想數一整類對象或幾類命中,那麼你可以有:

count = Hit.objects.filter(
        created__range = myrange, 
        content_type__in = set_of_types 
        ).count() 

set_of_types可以是與get_for_model電話或查詢構建列表通過直接過濾ContentType表獲得。

count()方法的好處在於它使得計數在數據庫中發生,速度更快。

要獲取CONTENT_TYPE細分試試這個:

counts = Hit.objects.filter(
        created__range = myrange 
       ).values(
        'content_type' 
       ).annotate(
        Count('content_type') 
       ) 

應該返回計數VS內容類型ID,相當接近你想要什麼的字典,。

+0

我使用此解決方案。我不確定它給了我什麼,但我想要的。而不是一個對象的命中數(給​​定一個時間範圍,content_type和object_id),我想要所有對象的命中數(給​​定一個時間範圍和content_type),以便我可以對它們進行排序。看來,即使按照您描述的方式重構models.py,我也不能同時使用annotate和content_object。 – 2010-11-19 18:14:25

+0

更新了我的帖子。好吧,我不會在這種情況下使用註釋,因爲你的查詢會做太多的工作,而且我認爲對於大集合來說,它很慢。海事組織在這種情況下計算懶惰的方法可能會更好。 – Evgeny 2010-11-19 18:35:45

+0

謝謝你的跟進。這仍然不能完成我的目標。有了這個,我仍然得到一個數字。我希望有一個可迭代的列表。假設我們在最後一塊代碼中忽略了.count(),我們會得到5個對象:一個是A類型的3個,另一個是B類型的2個。我想讓查詢給我2個對象,分別計數:A型(計數= 3)和B型(計數= 2)。不僅僅是5(這是我從上面的代碼中得到的)。 – 2010-11-19 20:53:22