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

如何实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:06:06