加快Django查询“最新”的ForeignKey相关对象

时间:2015-08-31 14:36:38

标签: mysql django django-models

使用Django,我有两个相关的模型。拨打第一个BaseObject。第二个叫做BaseObjectObservation,每6个小时左右我创建一个新的BaseObjectObservation,它通过ForeignKey链接到BaseObject,并且有另一个字段用于关于该对象的特定数据点那个时候,还有一个时间戳。

正如您所料,我一直感兴趣的是给定BaseObjectObservation的“最新”BaseObject。麻烦的是现在每个BaseObject都有很多观察结果,即使有~500 BaseObject s,加载一个包含所有BaseObject s的页面,每个人的最新观察结果都非常慢。

有关如何加快检索最新观察的任何建议?

奖金问题:我也对过去24小时内每个物体的观察结果发生了变化感兴趣。以前我试过查询最近的观察和最接近24小时前的观察并计算差异;这太慢了。这里有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

class BaseObject(models.Model):
    pass

class BaseObjectObservation(models.Model):
    base_object = models.ForeignKey(BaseObject, related_name="observations")
    last_modification = models.DateTimeField(auto_now=True)
    latest = models.BooleanField(default=False)

    def save(self, **kwargs)

        if not self.pk:
            # mark new instance as latest
            self.latest = True

            # Update previous observations
            self.base_object.observations.update(latest=False)

        super().save(**kwargs)

然后,如果您想获得基础对象的最新观察,您可以这样做:

BaseObjectObservation.objects.filter(latest=True).select_related('base_object')

select_related子句将为您节省500个查询,因为它将在观察时获取基础对象。

由于您在单个查询中执行所有操作,因此性能应该更好。但是,可能存在一些最干净的解决方案,而无需在每个实例上存储布尔值。

加成

对于你的奖金问题,你可能会得到some inspiration here

import datetime
from django.utils import timezone

24_hours_ago = timezone.now() - datetime.timedelta(hours=24)


current_observation = base_object.observations.get(latest=True)

closest_observation_greater = base_object.observations.filter(creation_date__gt=24_hours_ago).first()
closest_observation_lower = base_object.observations.filter(creation_date__lte=24_hours_ago).first()

if closest_observation_greater - target > target - closest_observation_lower:
    return closest_observation_lower
else:
    return closest_observation_greater

然而,对于每个观察,仍然有两个查询。你可以优化它,但你也可以减少它 每页显示的元素数。你真的需要在同一页面上显示500个元素吗?