如何修改ModelViewSet的数据展示格式?实现分支机构按国家分组
按国家分组返回分支机构数据的实现方案
方法一:重写视图list方法,从分支机构数据分组
步骤1:创建城市数据序列化器
定义仅序列化分支机构核心字段的序列化器,无需嵌套国家信息:
class FilialCitySerializer(serializers.ModelSerializer): class Meta: model = Filials fields = ['name', 'subdomain_name', 'address']
步骤2:重写视图list方法
在原有FilialsViewSet中重写list方法,实现分组逻辑:
from django.http import Response from itertools import groupby class FilialsViewSet(viewsets.ModelViewSet): # 提前关联country并排序,避免N+1查询,同时保证groupby能正确分组 queryset = Filials.objects.all().select_related('country').order_by('country__name') serializer_class = FilialsSerializer def list(self, request, *args, **kwargs): # 获取过滤后的查询集 queryset = self.filter_queryset(self.get_queryset()) # 按国家分组,生成目标格式数据 response_data = [] # 用country对象作为分组键,确保同一国家的分支机构被归为一组 for country, filial_group in groupby(queryset, key=lambda x: x.country): # 序列化当前国家下的所有分支机构 cities_data = FilialCitySerializer(filial_group, many=True).data response_data.append({ "country": country.name, "cities": cities_data }) return Response(response_data)
方法二:从国家模型出发,嵌套序列化分支机构
该方法更贴合分组后的逻辑结构,直接查询国家并关联下属分支机构:
步骤1:创建国家带分支机构的序列化器
class FilialCitySerializer(serializers.ModelSerializer): class Meta: model = Filials fields = ['name', 'subdomain_name', 'address'] class CountryWithFilialsSerializer(serializers.ModelSerializer): # 这里的source对应Filials模型中外键指向CountryFilials的反向关联名称,默认是`filials_set`,如果模型中设置了related_name则用对应值 cities = FilialCitySerializer(source='filials_set', many=True) class Meta: model = CountryFilials fields = ['name', 'cities']
步骤2:调整视图的查询集和序列化器
from django.http import Response class FilialsViewSet(viewsets.ModelViewSet): # 查询所有包含分支机构的国家,预加载下属分支机构避免N+1查询 queryset = CountryFilials.objects.filter(filials__isnull=False).distinct().prefetch_related('filials_set') serializer_class = CountryWithFilialsSerializer def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) serializer = self.get_serializer(queryset, many=True) # 调整格式,把name字段重命名为country response_data = [ {"country": item["name"], "cities": item["cities"]} for item in serializer.data ] return Response(response_data)
关键说明
- 两种方法均使用
select_related或prefetch_related避免数据库N+1查询问题,提升接口性能。 - 若
Filials模型中外键指向CountryFilials时设置了related_name(比如related_name='filials'),需将代码中的filials_set替换为对应的related_name值。
内容的提问来源于stack exchange,提问作者Pretty Cow
相关产品推荐
相关产品推荐

