2010-04-05 23 views
12

我很驚訝這個問題還沒有出現。無法在網上找到太多內容。Django相當於每個用戶的最新條目

使用Entry.objects.latest('created_at')我可以恢復所有Entry對象的最新條目,但是說我是否想爲每個用戶輸入最新條目?這與SQL最新記錄查詢類似。但是,如何使用ORM實現這一點?這是我的方法,我想知道它是否是最有效的方式來做我想要的。

首先我執行一個子查詢:對象按用戶分組,然後爲每個用戶返回Max(最新)created_by字段(created_at__max)然後根據子查詢中的結果過濾Entry對象並獲取所需的對象。

Entry.objects.filter(created_at__in=Entry.objects.values('user').annotate(Max('created_at')).values_list('created_at__max')) 

或使用經理:

class UsersLatest(models.Manager): 

    def get_query_set(self): 
     return super(UsersLatest,self).get_query_set().filter(created_at__in=self.model.objects.values('user').annotate(Max('created_at')).values_list('created_at__max')) 

有沒有更有效的方法?可能沒有子查詢?

感謝,

保羅

+1

我正在爲我的模型添加一個is_latest布爾值的想法,當我在form.save方法中保存一個新條目時設置了該布爾值,然後恢復以前的is_latest對象並使其成爲假 - 所以在那裏是每個條目保存的兩個步驟。我不知道這是否是最好的選擇。有什麼建議麼? – Paul 2010-04-09 20:37:21

回答

0

我不能想出一個原始的SQL查詢,這將獲取你所需要的設定,所以我懷疑它可以構建一個QuerySet與這些結果。

1

您的QuerySet的設計取決於您打算如何使用它。我不確定爲什麼在最後使用values_list方法突破QuerySet迭代器。我想你有一個用戶的狀態列表,顯示基於那個Entries模型的最後一次活動時間。對於您可能想試試這個:

Users.objects.all().annotate(latest_activity=Max('entries__created_at')) 
通過您的用戶輕鬆

然後循環在你的模板與

{% for user in users %} 
{{ user.full_name }} 
{{ user.latest_activity|date: "m/d/Y" }} 
{% endfor %} 
+0

嗨,感謝您的建議,好方法。 (Max('created_at'))返回包含'user'和'created_at__max'數據的字典列表,我使用values_list('created_at__max')將數據過濾到列表中,以便與created_at__in = – Paul 2010-04-09 20:32:43

1

原始SQL是

SELECT entry.id, entry.title, entry.content, entry.user_id, entry.created_at 
FROM 
    entry 
WHERE 
    entry.created_at = (SELECT Max(e2.created_at) from entry as e2 where e2.user_id = entry.user_id) 

那麼一個選項是使用extra() modifier的參數where

Entry.objects.extra(where='entry.created_at = (SELECT Max(e2.created_at) from entry as e2 where e2.user_id = entry.user_id)') 

當然,您可能必須將entry更改爲表中實際名稱在數據庫中的任何名稱。假設你看着舒服._meta,你可以試試這個:

Entry.objects.extra(where= 
    '%(table)s.created_at = (SELECT Max(e2.created_at) from %(table)s as e2 where e2.user_id = %(table)s.user_id)' % { 'table':Entry._meta.db_table } 
) 

有可能是一個更優雅的方式來獲得一個表的名稱。

+0

一起使用感謝您的建議,完全符合我的要求。 我使用._as_sql()檢查了我的Django查詢的sql,它幾乎完全相同 – Paul 2010-04-09 20:26:19

0

我有一個類似的問題,就是這麼做的:

priorities = obj.books_set.values('category').annotate(priority=Max('priority')) 

注:我批註最高優先級優先級,因爲我會重用輸出作爲過濾條件。

這是一個具有最小優先級的類別列表。然後,我這樣做:

>>> priorities[0] 
{'category': 1, 'priority': 10} 

我想找到的書有一個列表中&類優先對。最終的查詢集條件應該是這樣的:

Q(priorities[0]) | Q(priorities[1]) | ... 

要做到這一條線,使用reduceQ.__or__

reduce(Q.__or__, (Q(**x) for x in priorities)) 

我知道這是不是原始SQL差些,但更安全。如果您使用它,請註釋此代碼,因爲它很難閱讀。

3

使用order_by和​​:

Entry.objects.all().order_by('user', 'created_at').distinct('user') 

然後,對於性能上 '用戶' 和 'created_at' 字段添加索引在一起。

但我認爲真正的生產方式是使用Redis來緩存和更新用戶的最新條目的ID列表。