Django 外键聚合求和

0 投票
1 回答
620 浏览
提问于 2025-04-18 18:02

我有以下这些模型:

class Journey(models.Model):
      time = models.TimeField()
      distance = models.FloatField()

class Trip(models.Model):
      outward_journey = models.ForeignKey(Journey)
      return_journey = models.ForeignKey(Journey, null=True)

现在如果我有一份旅行的列表,我想知道所有旅行的总距离。

举个例子,我想把 outward_journey 的距离和 inward_journey 的距离加在一起。请问在Django中,这样做是否可行(无论是否使用 .extra() 语句)?我试过一些方法,比如:

 Trip.objects.all().aggregate(out=Sum('outward_journey__distance'), in=Sum('return_journey_distance'))`

这个方法给我返回了一个字典(我可以在Python中对这些值进行求和),但这并不是最理想的,因为 return_journey 可能是空的(对于单程旅行),所以 return_journey_distance 可能是 None。也就是说,我可能会得到一个像 {'outward_journey_distance' : 500, 'return_journey_distance' : None} 这样的字典。

我还尝试过:

Trip.objects.all().extra(select={'distance' : 'SUM(outward_journey.distance) + SUM(inward_journey.distance)'})

但这样我得到了 ProgrammingError: missing FROM-clause entry for table "outward_journey" 的错误。

使用Django的ORM,有什么更简单的方法来实现这个功能吗?(而不是单纯使用原始SQL)?

编辑:

我还有一个想法是先在Python中获取这些距离,然后用类似这样的方式进行求和,但如你所见,这样做并不理想/清晰:

 distances = Trip.objects.all().values_list('outward_journey__distance', 'inward_journey__distance')
 # gives distances = ((11, 1), (20, None), (2, 2) ...)
 total_distance = sum([sum([d for d in each_distance if d]) for each_distance in distances)])

1 个回答

0

你可以把两个查询结果结合起来,一个是单程旅行的,一个是往返旅行的,像这样:

round_trips = Trip.objects.exclude(return_journey__distance__isnull=True).aggregate(outward=Sum('outward_journey__distance'), inward=Sum('return_journey_distance'))
oneway_trips = Trip.objects.filter(return_journey__distance__isnull=True).aggregate(oneway=Sum('outward_journey__distance'))

要把这两个结合起来:

all_distances = dict(round_trips.items() + oneway_trips.items())

或者要计算总距离:

total_distance = round_trips.values() + oneway_trips.values()

撰写回答