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

如何使用Django QuerySet与Serializer按年月排序数据并生成指定格式的订单分组响应

嘿,作为Django REST Framework的新手,这个按年月分组序列化的需求其实不难,我一步步给你讲清楚怎么实现:

解决方案:按年月分组并序列化Order数据

1. 先搞定QuerySet的排序与分组准备

首先,我们需要从数据库里把Order数据取出来,并且按创建时间排序——这很重要,因为后面分组的时候需要相同月份的订单是连续的:

# 获取所有订单,按创建时间降序排列(最新的订单在前)
orders_queryset = Order.objects.all().order_by('-created_at')

如果你想先看看每个月有多少订单,可以用Django的数据库函数TruncMonth来做统计(这一步可选,主要是辅助了解数据):

from django.db.models import Count, TruncMonth

monthly_order_counts = Order.objects.annotate(
    month=TruncMonth('created_at')
).values('month').annotate(
    total_orders=Count('id')
).order_by('-month')

但要获取每个月的完整订单列表,我们更多会在Python代码层面用itertools.groupby来分组,因为QuerySet没法直接返回嵌套的订单列表结构。

2. 定义匹配JSON结构的Serializer

我们需要三层Serializer来对应你要的JSON格式:

2.1 订单子项Serializer

先写一个只序列化订单id的简单Serializer:

from rest_framework import serializers
from .models import Order

class OrderItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = ('id',)

2.2 月份分组Serializer

然后是每个月份分组的Serializer,包含格式化后的月份名称和对应的订单列表:

class OrderMonthSerializer(serializers.Serializer):
    month = serializers.CharField()
    order_list = OrderItemSerializer(many=True)

2.3 顶层Serializer

最后是包裹整个数组的顶层Serializer:

class MonthlyOrderListSerializer(serializers.Serializer):
    order_by_month_year = OrderMonthSerializer(many=True)

3. 在视图里完成分组与序列化

接下来在视图中把QuerySet的数据按年月分组,再传给Serializer输出:

from rest_framework.views import APIView
from rest_framework.response import Response
import itertools
from django.utils.dateformat import DateFormat

class MonthlyOrderView(APIView):
    def get(self, request):
        # 获取排序后的订单数据
        orders = Order.objects.all().order_by('-created_at')
        
        # 定义分组的key函数:把created_at转成"January 2021"这样的格式
        def month_group_key(order):
            date_formatter = DateFormat(order.created_at)
            return date_formatter.format('F Y')  # F是完整月份名,Y是4位年份
        
        # 按月份分组(注意:groupby要求数据已按key排序,所以前面的order_by必须有)
        grouped_data = []
        for month_name, order_group in itertools.groupby(orders, key=month_group_key):
            grouped_data.append({
                'month': month_name,
                'order_list': list(order_group)
            })
        
        # 用顶层Serializer序列化数据
        serializer = MonthlyOrderListSerializer(data={'order_by_month_year': grouped_data})
        serializer.is_valid(raise_exception=True)
        
        return Response(serializer.data)

几个关键注意点

  • 排序不能少:itertools.groupby只会把连续的相同key的元素分到一组,所以必须先让QuerySet按created_at排序,确保同一个月份的订单挨在一起。
  • 日期格式化要准确:用Django自带的DateFormat比Python原生的strftime更好,因为它会适配你项目的本地化设置(比如如果是中文环境,会自动显示“2021年1月”)。
  • Serializer的选择:因为我们的输出结构不是直接对应单个模型,所以顶层和月份分组的Serializer用自定义的serializers.Serializer,而订单子项用ModelSerializer更省心。

测试效果

启动Django服务后,访问这个视图的URL,就能得到你想要的JSON结构啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:47:38