Django如何从关联对象累加数值至主对象字段
问题
如何将多个关联对象中字段的整数值累加后,展示到主对象的指定字段中?具体需求为:将客户所有历史订单中的how_many_order字段值累加,输出到Customer对象的all_previous_orders字段中。
预期输出示例
[ { "customer_name": "John Doe", "orders": [ { "order_name": "fruit", "how_many_order": 10 }, { "order_name": "car", "how_many_order": 1 } ], "all_previous_orders": 11 } ]
现有代码
Models.py
class Customer(models.Model): customer_name = models.CharField(max_length=100) class Order(models.Model): customer = models.ForeignKey(Customer, on_delete=models.CASCADE) order_name = models.CharField(max_length=100) how_many_order = models.IntegerField(default=0)
Serializers.py
class OrderSerializer(serializers.ModelSerializer): class Meta: model = Order fields = '__all__' class CustomerSerializer(serializers.ModelSerializer): orders = OrderSerializer(many=True, read_only=True, required=False) class Meta: model = Customer fields = '__all__'
解决方案
方法1:序列化器中自定义字段计算
通过SerializerMethodField在序列化阶段直接计算订单总和:
from rest_framework import serializers from django.db.models import Sum class CustomerSerializer(serializers.ModelSerializer): orders = OrderSerializer(many=True, read_only=True, required=False) all_previous_orders = serializers.SerializerMethodField() def get_all_previous_orders(self, obj): # 数据库层面聚合求和,性能优于Python遍历 total = obj.order_set.aggregate(total=Sum('how_many_order'))['total'] return total if total is not None else 0 class Meta: model = Customer fields = ['customer_name', 'orders', 'all_previous_orders']
方法2:模型中定义属性字段
在Customer模型中新增属性,让模型自身具备计算能力:
修改Models.py
from django.db.models import Sum class Customer(models.Model): customer_name = models.CharField(max_length=100) @property def all_previous_orders(self): total = self.order_set.aggregate(total=Sum('how_many_order'))['total'] return total if total is not None else 0
修改Serializers.py
class CustomerSerializer(serializers.ModelSerializer): orders = OrderSerializer(many=True, read_only=True, required=False) all_previous_orders = serializers.ReadOnlyField() class Meta: model = Customer fields = ['customer_name', 'orders', 'all_previous_orders']
方法3:批量查询时预计算(性能最优)
如果需要批量查询客户,在视图中用annotate提前在数据库层面完成计算,减少查询次数:
视图示例
from django.db.models import Sum from rest_framework import generics from .models import Customer from .serializers import CustomerSerializer class CustomerListView(generics.ListAPIView): queryset = Customer.objects.annotate( all_previous_orders=Sum('order__how_many_order') ).all() serializer_class = CustomerSerializer
序列化器调整
只需确保字段列表包含all_previous_orders:
class CustomerSerializer(serializers.ModelSerializer): orders = OrderSerializer(many=True, read_only=True, required=False) class Meta: model = Customer fields = ['customer_name', 'orders', 'all_previous_orders']
内容的提问来源于stack exchange,提问作者mRezaAnanta
相关产品推荐
相关产品推荐

