Zac*_*ach 72 python django django-queryset greatest-n-per-group
我有两个型号A和B.所有B对象都有一个对象的外键A.给定一组A对象,无论如何都要使用ORM来获取B包含为每个A对象创建的最新对象的一组对象
这是一个简化的例子:
class Bakery(models.Model):
town = models.CharField(max_length=255)
class Cake(models.Model):
bakery = models.ForeignKey(Bakery, on_delete=models.CASCADE)
baked_at = models.DateTimeField()
Run Code Online (Sandbox Code Playgroud)
所以我正在寻找一个可以返回美国Anytown每家面包店最新蛋糕的查询.
Tom*_*ski 31
据我所知,在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]
)
Run Code Online (Sandbox Code Playgroud)
如果蛋糕的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)
Run Code Online (Sandbox Code Playgroud)
BTW为此归功于丹尼尔罗斯曼,曾经回答了我的类似问题:
如果上面的方法太慢,那么我也知道第二种方法 - 你可以编写自定义SQL,只生成那些在相关面包店中最热门的Cakes,将其定义为数据库VIEW,然后为它编写非托管Django模型.它也在上面的django-users线程中提到过.这里有与原始概念的直接链接:
希望这可以帮助.
Tod*_*dor 23
从开始Django 1.11并感谢子查询和OuterRef,我们终于可以建立一个latest-per-group使用查询ORM.
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))
Run Code Online (Sandbox Code Playgroud)
dbn*_*dbn 18
如果你碰巧使用的是PostGreSQL,你可以使用Django的DISTINCT ON接口:
recent_cakes = Cake.objects.order_by('bakery__id', '-baked_at').distinct('bakery__id')
Run Code Online (Sandbox Code Playgroud)
正如文档所说,你必须order by和你一样distinct on.正如Simon在下面指出的那样,如果你想进行额外的排序,你必须在Python空间中进行.
这应该做的工作:
from django.db.models import Max
Bakery.objects.annotate(Max('cake__baked_at'))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15237 次 |
| 最近记录: |