API端点性能改进

时间:2016-02-19 13:04:11

标签: django

我有一个API端点来返回每日驱动日志,并且它的扩展非常糟糕。我已将其缩小到名为on_duty_total的模型上的特定属性。

class DailyLog(models.Model):

    ... 

    @property
    def on_duty_total(self):
        # total time on-duty (statues of driving or on-duty)
        daily_log_entries = LogEntry.objects.filter(daily_log=self, status__in=["driving", "onduty"])
        total = 0

        if daily_log_entries:
            for entry in daily_log_entries:
                total = total + entry.minutes_duration

        # add time from the carry-over log entries
        for entry in self.carry_over_log_entries():
            tz_day_start = entry.tz_end_time.replace(hour=0, minute=0, second=0, microsecond=0)

            delta = entry.tz_end_time - tz_day_start
            minutes = delta.seconds / 60
            total = total + minutes

        # remove time from log entries that carry over to the next day
        for entry in self.overage_log_entries():
            tz_day_end = entry.tz_start_time.replace(hour=23, minute=59, second=59)

            delta = entry.tz_end_time - tz_day_end
            minutes = delta.seconds / 60
            total = total - minutes

        return total

我使用DRF通过API获取数据:

class DailyLogViewSet(ModelViewSet):
    serializer_class = DailyLogSerializer
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        return DailyLog.objects.filter(driver__user=self.request.user)

出现问题是因为对于每个日常日志,它需要进行数据库查询的on_duty_total(方法中的第一行)。例如,当用户拥有100个日常日志时,这意味着100个数据库查询,并且它会一直变得越来越慢。

坦率地说,我不确定如何解决这个问题,并且正在寻求创意。但是,我知道对计算属性上的每条记录运行db查询都不是一种选择。

1 个答案:

答案 0 :(得分:1)

据我所知,你实际上并不关心返回模型而只是用它来获得一个字段的总和,所以你可以聚合

daily_log_entries = LogEntry.objects.filter(daily_log=self, status__in=["driving", "onduty"])
daily_log_entries = daily_log_entries.aggregate(Sum('minutes_duration'))
total = daily_log_entries.minutes_duration__sum

我猜测大部分时间都是通过返回LogEntry对象中的每个值来实现的,这非常浪费,这只是消除了这种需要,只是按照你想要的那样做,并且在数据库方。