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

Django REST Framework嵌套模型如何按菜单分组聚合用户数据

解决方案

你的需求是按菜单维度聚合对应用户,原有实现是按订单维度返回,调整核心是把序列化主体从订单改为菜单,再自定义用户的返回格式即可,修改如下:


第一步:修改序列化器(serializers.py)

新增自定义的菜单序列化器,新增users字段实现你要的字典格式返回:

from rest_framework import serializers
from .models import Menu, Order

# 保留你原有UserSerializer不变
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username']

class MenuWithUsersSerializer(serializers.HyperlinkedModelSerializer):
    # 自定义users字段,用方法生成你要的字典结构
    users = serializers.SerializerMethodField()
    
    class Meta:
        model = Menu
        fields = ['id', 'food_name', 'users']
    
    def get_users(self, obj):
        # obj是当前菜单对象,获取所有关联订单的用户
        user_qs = User.objects.filter(id__in=obj.order_set.values_list('user_id', flat=True))
        user_list = UserSerializer(user_qs, many=True).data
        # 转成序号为键的字典,序号从1开始
        return {str(index+1): user for index, user in enumerate(user_list)}

如果你的Menu模型本身有原有Serializer,直接在原有基础上新增users字段和对应的get_users方法即可。


第二步:修改视图集(views.py)

把查询主体从订单改为菜单,使用新的序列化器:

from rest_framework import viewsets, response
from .models import Menu
from .serializers import MenuWithUsersSerializer

class MenuOrderViewSet(viewsets.ReadOnlyModelViewSet):
    # 预加载关联的订单和用户,避免N+1查询,提升性能
    queryset = Menu.objects.prefetch_related('order_set__user').all()
    serializer_class = MenuWithUsersSerializer

    # 给返回结果加一层menu包裹,匹配你要求的结构
    def list(self, request, *args, **kwargs):
        res = super().list(request, *args, **kwargs)
        res.data = [{"menu": item} for item in res.data]
        return res

如果你需要保留原有的订单增删改能力,可以不用修改原有OrderViewSet,新增上面这个视图集单独处理聚合查询的GET请求,单独配置路由即可。


可选方案:如果一定要保留OrderViewSet作为入口

可以重写OrderViewSet的list方法手动聚合数据,实现效果一致但性能略低于上面的方案:

from collections import defaultdict
from rest_framework import response

class OrderViewSet(viewsets.ModelViewSet):
    queryset = Order.objects.select_related('user', 'menu').all()
    serializer_class = OrderSerializer
    
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        menu_map = defaultdict(list)
        # 先按菜单分组所有用户
        for order in queryset:
            menu_map[order.menu].append(order.user)
        
        # 构造返回数据
        result = []
        for menu, users in menu_map.items():
            menu_data = MenuSerializer(menu).data
            menu_data['users'] = {str(index+1): UserSerializer(user).data for index, user in enumerate(users)}
            result.append({'menu': menu_data})
        
        return response.Response(result)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:54:01