Django中的嵌套子查询

时间:2017-06-07 11:53:14

标签: django django-aggregation django-subquery

使用Subquery进入深水区。我有一套Carpark s。 Carpark有多个Booking个。预订有许多BarrierActivity条记录,这些记录是障碍中各种即将到来的事件。这些都是堆栈中的简单FK。

预订可能会到达且障碍物相机识别它。一名工作人员会嗡嗡作响,但这意味着系统因某种原因失败了。这就是我在这里要做的事情。通过自动化方式计算出我预订的百分比。我知道有很多其他方法可以做到这一点,但我想用一个基于子查询的查询集来做这个。

我的目标相当简单。注释0或1以显示每个BarrierActivity是否存在“条目”Booking。根据{{​​1}}注释这些值的平均值。

第一部分没问题。我可以在CarparkExists()之间做一个简单的BarrierActivity,然后每个预订都有0或1:

Booking

再次,这很好。但是一旦我尝试将其扩展到另一个层(所以看successful_bas = BarrierActivity.objects.order_by().filter( booking=OuterRef('pk'), activity_type=BarrierActivity.TYPE_ANPR_BOOKING, direction='entry' ).values('booking') Booking.objects.order_by().annotate( entry_success=Exists(successful_bas) ) 而不是Carpark)...

Booking

...我得到了Subquery-of-doom:successful_bas = BarrierActivity.objects.order_by().filter( booking=OuterRef('pk'), activity_type=BarrierActivity.TYPE_ANPR_BOOKING, direction='entry' ).values('booking') bookings = Booking.objects.order_by().filter( carpark=OuterRef('pk') ).values('carpark').annotate( entry_success=Exists(successful_bas) ).values('entry_success') Carpark.objects.order_by().annotate( entry_hitrate=ExpressionWrapper( Avg(Cast(Subquery(bookings), IntegerField())) * 100, output_field=FloatField() ) ) more than one row returned by a subquery used as an expression子查询明显返回太多但是如何在它到达最外面的子查询之前聚合它?

我尝试了很多东西,但这里是对子查询中平均值的重组。同样的错误:

bookings

1 个答案:

答案 0 :(得分:0)

我能够在自己的一个项目中重新创建部分内容,并在外部子查询中添加distinct('<values_field_name>').order_by()解决了它。

需要使用distinct调用来减少返回的行数。不同调用中的字段名称是必需的,否则它会尝试跨另一个字段执行不同的调用。然后order_by()调用清除任何排序,以便查询对与初始表达式排序匹配的distinct表达式进行排序。

这是我尝试的:

successful_bas = BarrierActivity.objects.order_by().filter(
    booking=OuterRef('pk'),
    activity_type=BarrierActivity.TYPE_ANPR_BOOKING,
    direction='entry'
).values('booking')

bookings = Booking.objects.order_by().filter(
    carpark=OuterRef('pk')
).annotate(
    entry_success=Exists(successful_bas)
).values('carpark').distinct('carpark').order_by()

Carpark.objects.order_by().annotate(
    entry_hitrate=ExpressionWrapper(
        Avg(Cast(Subquery(bookings), IntegerField())) * 100,
        output_field=FloatField()
    )
)

请注意,我删除了外部子查询中的values调用之一。