我有一个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查询都不是一种选择。
答案 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对象中的每个值来实现的,这非常浪费,这只是消除了这种需要,只是按照你想要的那样做,并且在数据库方。