Получение последнего связанного элемента для каждого элемента в QuerySet
У меня есть простая модель Observation, сделанная Sensor:
class Observation(models.Model):
class ObservationType(models.TextChoices):
PM25 = 'pm25_kal', 'PM2,5'
PM10 = 'pm10_kal', 'PM10'
RH = 'rh', _('Relative humidity')
TEMP = 'temp', _('Temperature')
date_time = models.DateTimeField()
sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE)
obs_type = models.CharField(max_length=8, choices=ObservationType.choices)
value = models.DecimalField(max_digits=6, decimal_places=3)
Что я хочу сделать, так это получить list или QuerySet с последними Observation определенного типа, которые, по крайней мере, должны были быть созданы в течение 24 часов, для каждого датчика. Я решил эту проблему, используя метод модели для моей модели Sensor и пользовательский QuerySet для моей модели Observation, для фильтрации последних наблюдений.
class ObservationQuerySet(models.query.QuerySet):
def recent(self):
return self.filter(date_time__gte=timezone.now() - timedelta(days=1))
def latest_recent_observation(self, obs_type):
try:
return self.observation_set.filter(obs_type=obs_type).recent().latest('date_time')
except Observation.DoesNotExist:
return None
Я могу перебрать все датчики и получить latest_recent_observation() для каждого из них, но для больших наборов данных это довольно медленно. Есть ли способ сделать это более эффективным?
В конце концов я разобрался с этим сам. Я использовал аннотацию для получения значения последнего недавнего наблюдения.
latest_observation = Subquery(Observation.objects.filter(sensor_id=OuterRef('id'), obs_type=obs_type)
.recent()
.order_by('-date_time')
.values('value')[:1])
С этим я могу использовать annotate() на Queryset моей Sensor модели, которая возвращает новую Queryset со значением последней Observation данной Sensor.
sensors = Sensor.objects.all().annotate(latest_observation=latest_observation)