如何实现Django关联模型聚合数据自定义过滤器 支持URL年份参数筛选
解决步骤
1. 调整视图,传递URL参数到序列化器上下文
修改views.py中的PersonViewSet,重写get_serializer_context方法,将请求中的year参数传入序列化器上下文:
class PersonViewSet(viewsets.ModelViewSet): queryset = Person.objects.all() serializer_class = PersonSerializer def get_serializer_context(self): context = super().get_serializer_context() # 从URL查询参数中提取year,不存在则为None context['year'] = self.request.query_params.get('year') return context
2. 改造序列化器,实现动态过滤
修改serializers.py中的PersonSerializer,将固定的hikes字段改为动态过滤的SerializerMethodField,同时调整总里程计算逻辑根据上下文的year参数过滤:
from django.db.models import Sum class PersonSerializer(serializers.ModelSerializer): # 把固定的hikes字段改为动态计算的SerializerMethodField hikes = serializers.SerializerMethodField() total_miles = serializers.SerializerMethodField() def get_hikes(self, obj): year = self.context.get('year') # 过滤对应年份的徒步记录,没有传year就返回所有 hike_qs = obj.hikes.all() if year: hike_qs = hike_qs.filter(hike_date__year=year) # 返回主键列表 return hike_qs.values_list('id', flat=True) def get_total_miles(self, obj): year = self.context.get('year') hike_qs = obj.hikes.all() if year: hike_qs = hike_qs.filter(hike_date__year=year) result = hike_qs.aggregate(total=Sum('distance_mi')) # 处理没有匹配记录的情况,返回0避免报错 return round(result['total'] or 0, 2) class Meta: model = Person fields = ('id','first_name','last_name','hikes','total_miles')
效果验证
- 不带year参数请求
http://localhost:8000/persons/2/:返回所有年份的徒步记录id和总里程,和原有逻辑一致 - 带
year=2020请求:返回hikes: [2]、total_miles: 4.5 - 带
year=2021请求:返回hikes: [3,5,7]、total_miles: 12.9
完全匹配需求,同时满足hikes字段的拓展过滤要求。
内容的提问来源于stack exchange,提问作者lar-mo
相关产品推荐
相关产品推荐

