Как получить модели с наибольшим значением, сгруппированные по родственной модели в Django? - PullRequest
2 голосов
/ 08 марта 2019

Я бы хотел выполнить этот запрос в django:

For each sensor, select it's latest message

В SQL это будет что-то вроде

SELECT * FROM (SELECT * FROM messages order by date_entered DESC) as order GROUP BY sensor_id

Модели определены так:

class BaseModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    date_entered = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    deleted = models.IntegerField(default=0)

    class Meta:
        abstract = True
        ordering = ['date_modified']

class Device(BaseModel):

    user =              models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)

    name =              models.CharField(max_length=255, blank=False)
    identifier =        models.CharField(max_length=31, blank=False)
    imei =              models.CharField(max_length=31, blank=False)
    status =            models.CharField(max_length=31, blank=False)
    settings =          models.TextField()


class DeviceMessage(BaseModel):


    device =            models.ForeignKey(Device, on_delete=models.SET_NULL, blank=True, null=True)
    user =              models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)

    latitude =          models.DecimalField(max_digits=9, decimal_places=6, blank=True, null=True)
    longitude =         models.DecimalField(max_digits=9, decimal_places=6, blank=True, null=True)
    altitude =          models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True)
    signal_strength =   models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True)
    battery =           models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True)

    satellites =        models.IntegerField(blank=True, null=True)
    size =              models.IntegerField(blank=True, null=True)

    raw =               models.TextField(blank=True, null=True)

Можно ли добиться этого в Джанго?

По сути, именно эта проблема Использование ORDER BY и GROUP BY вместе

Ответы [ 2 ]

1 голос
/ 08 марта 2019

Начиная с Django 1.11, есть функция Подзапрос , которую можно использовать для аннотирования данных:

from django.db.models import OuterRef, Subquery

latest = DeviceMessage.objects.filter(device_id=OuterRef('pk')).order_by('-date_entered')

devices = Device.objects.annotate(latest_message_id=Subquery(latest.values('pk')[:1]))
message_ids = [d.latest_message_id for d in devices]
for message in DeviceMessage.objects.filter(pk__in=message_ids).select_related('device'):
    print(device.name, message)

......

0 голосов
/ 08 марта 2019

«Для каждого датчика выберите его последнее сообщение»

Я предполагаю, что под «датчиком» вы ссылаетесь на модель Device.В этом случае (так как вы теперь пояснили, что BaseModel был абстрактным базовым классом), это так просто (с sensor являющимся конкретным Device экземпляром, о котором вы спрашиваете):

sensor.devicemessage_set.order_by("-date_entered")[0]

Если вы хотите найти эту информацию для нескольких датчиков одновременно, вам лучше использовать аннотацию , например:

from django.db.models import Max
...
Device.objects.all().annotate(latest_msg=Max("devicemssage_set__date_entered"))

Это дает каждый Device объект (временное) свойство с именем latest_msg, которое содержит необходимую информацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...