Django多模型关联查询:获取当前用户各设备最新Report
解决方法:获取用户每台设备的最新Report
方法一:使用Subquery(高效兼容多数据库)
这是性能最优的方案,适合数据量较大的场景,兼容MySQL、PostgreSQL等主流数据库。
首先导入所需模块:
from django.db.models import Subquery, OuterRef
然后构建查询:
# 子查询:获取每个设备最新Report的ID latest_report_ids = Report.objects.filter( device_id=OuterRef('pk') ).order_by('-date').values('pk')[:1] # 筛选当前用户的设备,并关联最新Report的ID user_devices = Device.objects.filter(owner=request.user).annotate( latest_report_id=Subquery(latest_report_ids) ) # 最终获取所有最新的Report记录 latest_reports = Report.objects.filter( pk__in=user_devices.values('latest_report_id') ).select_related('device_id')
方法二:使用distinct + order_by(代码简洁,依赖数据库特性)
此方法仅支持PostgreSQL(MySQL不支持带字段的distinct),代码最简洁:
latest_reports = Report.objects.filter( device_id__owner=request.user ).order_by('device_id', '-date').distinct('device_id')
原理:先按设备分组,再按日期倒序排序,distinct('device_id')会保留每个设备的第一条(最新)记录。
方法三:循环查询(直观但低效)
如果设备数量很少,可以用这种直观但有N+1查询问题的方式,不推荐大量设备场景:
user_devices = Device.objects.filter(owner=request.user) latest_reports = [] for device in user_devices: # 获取当前设备的最新Report latest_report = device.report_set.order_by('-date').first() if latest_report: latest_reports.append(latest_report)
额外优化建议
模型中Report的外键字段名device_id容易和Device的device_id字段混淆,建议修改命名规范:
class Report(models.Model): # 重命名外键字段,添加related_name方便反向查询 device = models.ForeignKey('Device', on_delete=models.CASCADE, related_name='reports') coordinates = models.JSONField(null=True) fill = models.IntegerField() date = models.DateTimeField() def __str__(self): return str(self.device.device_id)
之后可以用device.reports替代device.report_set,代码可读性更高。
内容的提问来源于stack exchange,提问作者Jaime
相关产品推荐
相关产品推荐

