从不同类别获取最新对象的Django查询

我有两个模型AB 所有的B对象都有一个到A对象的外键。 给定一组A对象,是否有使用ORM来获取包含为每个A对象创build的最近对象的一组B对象

这是一个简单的例子:

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

所以我正在寻找一个查询,返回美国Anytown每家面包店出炉的最新蛋糕。

据我所知,在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) 

顺便说一下,丹尼尔·罗斯曼曾经回答过类似的问题:

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

如果上面的方法太慢,那么我也知道第二种方法 – 你可以编写自定义的SQL,只生成相关面包房中最热门的Cakes,将其定义为数据库VIEW,然后为其编写非托pipeDjango模型。 在上面的django-users线程中也提到了这一点。 直接链接到原来的概念是这里:

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

希望这可以帮助。

如果您碰巧使用PostGreSQL,则可以使用Django的界面DISTINCT ON :

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

正如文件所说,你必须order by与你distinct on领域order by 。 正如Simon在下面指出的那样,如果您想进行额外的sorting,则必须在Python空间中执行此操作。

这应该做的工作:

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

Django 1.11开始,感谢Subquery和OuterRef ,最后我们可以使用ORM构build一个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)) 

我正在与类似的问题斗争,最后得出以下解决scheme。 它不依赖于order_bydistinct所以可以根据需要在db端进行sorting,也可以用作嵌套查询进行过滤。 我也相信这个实现是独立于数据库引擎的,因为它基于标准的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')) 
 Cake.objects.filter(bakery__town="Anytown").order_by("-created_at")[:1] 

我没有build立我的模型,但理论上这应该工作。 分解:

  • Cake.objects.filter(bakery__town="Anytown")假定该国不属于任何string,应归还属于“Anytown”的所有蛋糕。 bakerytown之间的双重下划线允许我们访问bakerytown财产。
  • .order_by("-created_at")会根据结果的创builddate,最近的第一个(注意"-created_at"中的- (减号)符号),如果没有减号,最近。
  • [:1]在结束时将只返回列表中返回的第一个项目(这将是来自Anytown的蛋糕列表,按照最近的sorting)。

注意:这个答案是为Django 1.11。 这个答案从Django 1.11文档中的查询修改。