2009-08-18 46 views
2

我有以下方式Django模型建立:Django的查詢一大批關係

模型中的有一個一對多的關係模型B

A中的每個記錄有間3000〜15000 B中的記錄

構建一個查詢的最佳方法是什麼,它將檢索B中對應於A中每個記錄中A記錄的最新(最大pk)記錄?這是我必須使用SQL來代替Django ORM嗎?

回答

2

安全地提取「頂」創建一個輔助函數來自任何查詢集的項目。我在我自己的Django應用程序中使用它。

def top_or_none(queryset): 
    """Safely pulls off the top element in a queryset""" 
    # Extracts a single element collection w/ top item 
    result = queryset[0:1] 

    # Return that element or None if there weren't any matches 
    return result[0] if result else None 

這使用了一點技巧w/slice operator to add a limit clause onto your SQL

現在,您可以在需要獲取查詢集的「頂部」項目的任何位置使用此功能。在這種情況下,你想要得到的高音B項爲給定的A,其中的B的被降PK排序,例如:

latest = top_or_none(B.objects.filter(a=my_a).order_by('-pk')) 

也有在Django Aggregation最近添加的「最大」的功能,可以幫助您得到最大pk,但我不喜歡這種解決方案,因爲它增加了複雜性。

P.S.我不太喜歡依賴這種查詢的'pk'字段,因爲有些RDBMS不能保證順序pks與邏輯創建順序相同。如果我有一張表,我知道我需要以這種方式查詢,我通常有我自己的「創建」日期時間列,我可以使用它來代替pk進行排序。

編輯基於評論:

如果你想用的查詢集[0],可以修改正是如此的 'top_or_none' 功能:

def top_or_none(queryset): 
    """Safely pulls off the top element in a queryset""" 
    try: 
     return queryset[0] 
    except IndexError: 
     return None 

我起初並沒有提出這個因爲我的印象是queryset [0]會撤回整個結果集,然後取第0項。顯然,Django在這種情況下也添加了「LIMIT 1」,所以它是我的切片版本的安全替代品。

編輯2

當然,你也可以利用Django的相關管理者的構建這裏通過你的「A」的對象創建的查詢集,根據自己的喜好:

latest = top_or_none(my_a.b_set.order_by('-pk')) 
+0

什麼 result = queryset [0:1] 和 result = queryset [0]之間的差異? – hekevintran 2009-08-19 02:37:21

+0

queryset [0:1]在沒有匹配的項目時將返回空列表,而queryset [0]將拋出IndexError。 – 2009-08-19 13:48:04

+0

感謝您的回答! – hekevintran 2009-08-19 15:22:30

0

我不認爲Django ORM可以做到這一點(但我之前一直驚喜......)。如果有一個合理數量的A記錄(或者如果你是分頁),我只需要向A模型添加一個方法,它將返回這個'最新'的B記錄。如果你想獲得大量的A記錄,每個記錄都有自己最新的B,那麼我會選擇SQL。

remeber,無論你採取哪條路線,你需要基於B表合適複合指數,也許增加一個order_by=('a_fk','-id')Meta