2010-01-15 87 views
51

我有兩個模型AB。所有B對象都有一個A對象的外鍵。給定一組A對象的,反正是有使用ORM獲得包含每個A對象從不同類別獲取最新對象的Django查詢

這裏創建的最新對象的一組B對象是一個簡化的例子:

Class Bakery(models.Model): 
    town = models.CharField() 

Class Cake(models.Model): 
    bakery = models.ForeignKey(Bakery) 
    baked_at = models.DateTimeField() 

所以我m查找返回美國Anytown每家麪包店烘烤的最新蛋糕的查詢。

+6

我很想看到這個:-) – gruszczy 2010-01-15 20:30:42

回答

26

據我所知,有在Django ORM這樣做的沒有一步到位的方式。

但是你可以在兩個查詢拆呢:

bakeries = Bakery.objects.annotate(hottest_cake_baked_at=Max('cake__baked_at')) 
hottest_cakes = Cake.objects.filter(baked_at__in=[b.hottest_cake_baked_at for b in bakeries]) 

如果ID蛋糕的與bake_at時間戳一起進步,可以簡化和澄清對上面的代碼(如果兩個月餅到達同一時間,你可以得到他們兩人):

hottest_cake_ids = Bakery.objects.annotate(hottest_cake_id=Max('cake__id')).values_list('hottest_cak‌​e_id', flat=True) 
hottest_cakes = Cake.objects.filter(id__in=hottest_cake_ids) 

BTW學分此去丹尼爾·羅斯曼,誰曾回答我的類似的問題:

http://groups.google.pl/group/django-users/browse_thread/thread/3b3cd4cbad478d34/3e4c87f336696054?hl=pl&q=

如果上面的方法太慢,那麼我也知道第二種方法 - 您可以編寫自定義SQL,只生成相關Bakeries中最熱門的Cakes,將其定義爲數據庫VIEW,然後編寫非託管Django模型它。在上面的django-users線程中也提到了它。直接鏈接到原始概念是在這裏:

http://web.archive.org/web/20130203180037/http://wolfram.kriesing.de/blog/index.php/2007/django-nice-and-critical-article#comment-48425

希望這有助於。

+0

我可能會用你建議的第二組查詢。謝謝。 – Zach 2010-01-18 16:08:10

+0

這會更有效率,你使用value_list作爲第一個查詢:hottest_cake_ids = Bakery.objects.annotate(hottest_cake_id = Max('cake__id'))。values_list('hottest_cake_id',flat = True); hottest_cakes = Cake.objects.filter(id__in = hottest_cake_ids) – dbn 2014-06-27 22:19:42

+0

此外,如果您碰巧使用PostGreSQL,則有一個解決方案。 – dbn 2015-01-30 12:34:01

4

這應該做的工作:

from django.db.models import Max 
Bakery.objects.annotate(Max('cake__baked_at')) 
+0

這很好,最後必須學習這些註釋。 – gruszczy 2010-01-15 20:37:23

+4

我還沒有測試,但看起來它會註釋每個麪包店最近烤蛋糕的時間。我正在尋找真正的蛋糕對象。我誤解了你的答案? – Zach 2010-01-15 21:11:07

+0

@Zach:不,我認爲你是對的 – 2010-01-16 07:53:06

15

如果你碰巧使用PostgreSQL,你可以使用Django's interface to DISTINCT ON

recent_cakes = Cake.objects.order_by('bakery__id', '-baked_at').distinct('bakery__id') 

由於the docs說,你必須order by相同的字段,你distinct on。正如Simon在下面指出的那樣,如果你想進行額外的排序,你必須在Python空間中完成。

+0

喜歡這種方式 - 謝謝。剛做了一個關於最終訂購的小修改。根據QS的總大小,這可能比接受的答案好或差。在我的情況:更好:) – 2015-01-24 11:48:01

+0

我認爲這是一個不必要的代碼複雜化,並超出了回答。我將假設人們可以弄清楚如何對結果數據進行排序。 – dbn 2015-01-30 12:29:17

+0

我玩了很多類似的問題,嘗試'Max'註釋和過濾他們,但他們最終失敗,因爲在django優化器刪除order_by(當使用結果作爲篩選子查詢或聚合時, .Count之間()')。這個解決方案在獲取'recent_cakes.count()'時不會破壞所有的東西,並且在執行'Cake.objects.filter(pk__in = recent_cackes).filter(other_conditions)'時不會拋出錯誤,但最新的例子返回_random_每個麪包店的蛋糕滿足other_conditions(不是最熱!),因爲django從子查詢中刪除'order_by' :( – 2015-04-01 04:48:15

2

我在與類似的問題鬥爭,最後得出以下解決方案。它不依賴於order_bydistinct,所以可以根據需要在數據庫端進行排序,也可以用作嵌套查詢進行過濾。我也相信這個實現是獨立於數據庫引擎的,因爲它基於標準sql HAVING子句。唯一的缺點是,如果它們在同一時間在麪包店烤制,它將返回每個麪包店的多個最熱的蛋糕。

from django.db.models import Max, F 

Cake.objects.annotate(
    # annotate with MAX "baked_at" over all cakes in bakery 
    latest_baketime_in_bakery=Max('bakery__cake_set__baked_at') 
    # compare this cake "baked_at" with annotated latest in bakery 
).filter(latest_baketime_in_bakery__eq=F('baked_at')) 
4

Django 1.11和感謝開始SubqueryOuterRef,我們可以使用ORM最終建立一個latest-per-group查詢。

hottest_cakes = Cake.objects.filter(
    baked_at=Subquery(
     (Cake.objects 
      .filter(bakery=OuterRef('bakery')) 
      .values('bakery') 
      .annotate(last_bake=Max('baked_at')) 
      .values('last_bake')[:1] 
     ) 
    ) 
) 

#BONUS, we can now use this for prefetch_related() 
bakeries = Bakery.objects.all().prefetch_related(
    Prefetch('cake_set', 
     queryset=hottest_cakes, 
     to_attr='hottest_cakes' 
    ) 
) 

#usage 
for bakery in bakeries: 
    print 'Bakery %s has %s hottest_cakes' % (bakery, len(bakery.hottest_cakes)) 
0
Cake.objects.filter(bakery__town="Anytown").order_by("-created_at")[:1] 

我還沒建出來我到底該機型,但在理論上這應該工作。分解:

  • Cake.objects.filter(bakery__town="Anytown")應歸還屬於「Anytown」的任何蛋糕,假定該國不屬於該字符串的一部分。 bakerytown之間的雙下劃線允許我們訪問bakerytown財產。
  • .order_by("-created_at")將責令其按創建日期的結果,最近的第一(請注意-(減號)在"-created_at",沒有減號,他們會用最古老的責令最近。
  • [:1]上年底將在返回列表中只返回第一個項目(這是從北京市東城蛋糕的列表,通過最近的第一排序)

注:這個答案是對的Django 1.11 。查詢顯示爲here in Django 1.11 Docs

相關問題