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

Django Admin中用Group By重写get_queryset报错求助

问题原因

你返回的是values()生成的字典类型QuerySet,但Django Admin的ModelAdmin默认要求返回模型实例的QuerySet。当Admin渲染list_display中的外键字段(order_unit、status)时,内部会自动调用select_related优化查询,而values()后的QuerySet不支持后续调用select_related,因此触发了该错误。

解决方案

推荐通过自定义变更列表模板的方式实现分组统计展示,这种方式更贴合汇总数据的展示需求,同时避开Admin对实例QuerySet的依赖。

步骤1:修改Admin类配置

取消注释自定义模板路径,并重写changelist_view方法获取分组统计数据:

@admin.register(models.OrderSummary)
class OrderSummaryAdmin(admin.ModelAdmin):
    change_list_template = 'admin/order_summary_change_list.html'
    date_hierarchy = 'created'
    show_full_result_count = False
    list_filter = (
        ('created', DateRangeFilter),
        ('order_unit__name', MultiSelectFilter),
        ('status__name', MultiSelectFilter),
    )

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        
        # 获取经过筛选后的基础查询集
        qs = self.get_queryset(request)
        # 按订单单元、状态分组统计订单数量
        grouped_data = qs.values(
            'order_unit__id', 'order_unit__name', 
            'status__id', 'status__name'
        ).annotate(total=Count('id')).order_by('order_unit__name', 'status__name')
        
        # 将统计数据传入模板
        extra_context['grouped_data'] = grouped_data
        return super().changelist_view(request, extra_context=extra_context)

步骤2:创建自定义变更列表模板

在项目模板目录下创建admin/order_summary_change_list.html,继承默认Admin模板并替换结果列表区域:

{% extends "admin/change_list.html" %}

{% block result_list %}
    <div class="results">
        <table>
            <thead>
                <tr>
                    <th>订单单元</th>
                    <th>状态</th>
                    <th>总数量</th>
                </tr>
            </thead>
            <tbody>
                {% for item in grouped_data %}
                <tr>
                    <td>{{ item.order_unit__name }}</td>
                    <td>{{ item.status__name }}</td>
                    <td>{{ item.total }}</td>
                </tr>
                {% empty %}
                <tr><td colspan="3">暂无匹配数据</td></tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
{% endblock %}
备选方案(小数据量场景)

如果数据量较小,也可以通过返回实例QuerySet+自定义显示字段的方式实现,但性能略差:

@admin.register(models.OrderSummary)
class OrderSummaryAdmin(admin.ModelAdmin):
    date_hierarchy = 'created'
    show_full_result_count = False
    list_display = ("get_order_unit", "get_status", "total_count")
    list_filter = (
        ('created', DateRangeFilter),
        ('order_unit__name', MultiSelectFilter),
        ('status__name', MultiSelectFilter),
    )

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        # 预缓存分组统计结果
        self.stats_map = {
            (item['order_unit__id'], item['status__id']): item['total']
            for item in qs.values('order_unit__id', 'status__id').annotate(total=Count('id'))
        }
        # 返回去重后的实例QuerySet(仅支持PostgreSQL)
        return qs.select_related('order_unit', 'status').distinct('order_unit__id', 'status__id')

    def get_order_unit(self, obj):
        return obj.order_unit.name
    get_order_unit.short_description = "订单单元"

    def get_status(self, obj):
        return obj.status.name
    get_status.short_description = "状态"

    def total_count(self, obj):
        return self.stats_map.get((obj.order_unit.id, obj.status.id), 0)
    total_count.short_description = "总数量"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 21:32:40