简体   繁体   中英

Django annotate related field

I want to optimize a simple django query to prefetch all the latest values.

sensors = Sensor.objects.all()

Here is the model:

class Sensor:
    last_record_at = models.DateTimeField(null=True, blank=True)

class Record:
    value = models.FloatField()
    sensor = models.ForeignKey('hardware.Sensor', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)

Before, Sensor model had a foreign key (last record) to record and all the records could be retrieved simply by adding:

.select_related('last_record')

To optimize the database, I removed that foreign key and replaced it with a datetime field named last_record_at.

I am using Django 2.0 and I am wondering if there is a pretty ORM way to retrieve all the sensors and last records in one (or two) query using subqueries, annotation or prefetching.

Something like (it does not work):

record_sub_query = Record.objects.filter(
    created=OuterRef('last_record_at'), 
    sensor_id=OuterRef('pk')
) 
sensors = Sensor.objects.all().annotate(
    last_record=Subquery(record_sub_query[:1])
)   

or using prefetch:

sensors = Sensor.objects.all().prefetch_related(
    Prefetch(
        'records', 
        queryset=Record.objects.filter(created=F('sensor__last_record_at'))
    )
)

The only alternative I see is writing Raw SQL for this rather simple problem.

I would do it the other way around: you currently try to retrieve all Sensors , then get their latest associated Record . Why not retrieve all Records that have a Sensor such that sensor.last_record_at == record.created ?

This way:

Records.objects.filter(sensor__last_record_at=F('created')).select_related('sensor')

would do the job.

This assumes you never have two records at the same time for a given sensor, otherwise, you could get several times the same Sensor , and that every Sensor has a Record with the last_record_at date.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM