You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django查询:按模型属性分组并保留每组最新记录

Django按project分组获取每个分组最新记录的正确实现

模型定义

class Building(models.Model):
    building_id = models.AutoField(primary_key=True)
    created_at = models.DateTimeField(auto_now_add=True, blank=True)
    project = models.CharField(max_length=200, blank=True, null=True)

现有方案问题

方案1:循环查询生成字典

这种方式生成的字典结构,无法直接用{% for i in projects %}的列表遍历语法在模板中使用,同时处理关联对象的pk时也会有不便。

方案2:全局最新记录

用project__in搭配latest只能拿到全局范围内最新的单条记录,无法实现按project分组获取各自最新记录的需求。

正确实现方法

方法1:改造循环逻辑,生成可遍历列表

把字典结构换成列表,每个元素包含项目名和对应最新记录对象,适配模板遍历需求:

# 排除空项目(可选,根据业务需求调整)
projects = Building.objects.exclude(project__isnull=True).values_list('project', flat=True).distinct()
latest_buildings = []
for project in projects:
    latest = Building.objects.filter(project=project).latest('created_at')
    latest_buildings.append({
        'project_name': project,
        'building': latest
    })
context['latest_buildings'] = latest_buildings

模板中使用示例:

{% for item in latest_buildings %}
    <p>项目:{{ item.project_name }}</p>
    <p>最新记录ID:{{ item.building.building_id }}</p>
    <p>创建时间:{{ item.building.created_at }}</p>
    <!-- 正常使用pk生成跳转链接 -->
    <a href="{% url 'building_detail' item.building.building_id %}">查看详情</a>
{% endfor %}

该方法逻辑直观,适合数据量不大的场景。

方法2:数据库聚合+子查询,高效查询

针对数据量较大的场景,用Subquery和OuterRef实现单次数据库查询,避免循环多次查询的性能损耗:

from django.db.models import Subquery, OuterRef, Max

# 子查询:获取每个project对应的最新创建时间
max_created_subquery = Building.objects.filter(
    project=OuterRef('project')
).values('project').annotate(max_created=Max('created_at')).values('max_created')

# 主查询:筛选出每个project中创建时间等于对应最大值的记录
latest_buildings = Building.objects.annotate(
    max_created=Subquery(max_created_subquery)
).filter(created_at=models.F('max_created')).distinct('project')

context['latest_buildings'] = latest_buildings

模板中直接遍历QuerySet即可:

{% for building in latest_buildings %}
    <p>项目:{{ building.project }}</p>
    <p>最新记录ID:{{ building.building_id }}</p>
    <p>创建时间:{{ building.created_at }}</p>
    <a href="{% url 'building_detail' building.building_id %}">查看详情</a>
{% endfor %}

MySQL适配提示:如果使用MySQL,distinct('project')不支持,可改用按id关联的写法:

# MySQL适配写法
max_ids = Building.objects.values('project').annotate(max_id=Max('building_id')).values('max_id')
latest_buildings = Building.objects.filter(building_id__in=max_ids)

该方法仅需1-2次数据库查询,性能更优。


内容的提问来源于stack exchange,提问作者Murcielago

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 20:45:29