在Django Rest Framework序列化器中聚合(和其他已注释的)字段
在Django Rest Framework序列化器中聚合(和其他已注释的)字段
我正在寻找一种最佳方式来向DRF(Model)Serializers中添加带注释的字段,如任何聚合(计算)字段。我的场景是简单地情况下,一个端点返回的字段并不存储在数据库中,而是从数据库中计算得出的。
让我们看下面的例子:
models.py
class IceCreamCompany(models.Model): name = models.CharField(primary_key=True, max_length=255) class IceCreamTruck(models.Model): company = models.ForeignKey('IceCreamCompany', related_name='trucks') capacity = models.IntegerField()
serializers.py
class IceCreamCompanySerializer(serializers.ModelSerializer): class Meta: model = IceCreamCompany
期望的JSON输出:
[
{
"name": "Pete's Ice Cream",
"total_trucks": 20,
"total_capacity": 4000
},
...
]
我有几个解决方案可以工作,但每个都有一些问题。
选项1:在模型中添加getter并使用SerializerMethodFields
models.py
class IceCreamCompany(models.Model): name = models.CharField(primary_key=True, max_length=255) def get_total_trucks(self): return self.trucks.count() def get_total_capacity(self): return self.trucks.aggregate(Sum('capacity'))['capacity__sum']
serializers.py
class IceCreamCompanySerializer(serializers.ModelSerializer): def get_total_trucks(self, obj): return obj.get_total_trucks def get_total_capacity(self, obj): return obj.get_total_capacity total_trucks = SerializerMethodField() total_capacity = SerializerMethodField() class Meta: model = IceCreamCompany fields = ('name', 'total_trucks', 'total_capacity')
上述代码可以进行一些重构,但这不会改变这个选项每个IceCreamCompany执行2个额外的SQL查询,这不太高效。
选项2:在ViewSet.get_queryset中进行注释
models.py如上所述。
views.py
class IceCreamCompanyViewSet(viewsets.ModelViewSet): queryset = IceCreamCompany.objects.all() serializer_class = IceCreamCompanySerializer def get_queryset(self): return IceCreamCompany.objects.annotate( total_trucks=Count('trucks'), total_capacity=Sum('trucks__capacity') )
这将在单个SQL查询中获取聚合字段,但我不确定如何将它们添加到Serializer中,因为DRF并不会自动知道我在QuerySet中注释了这些字段。如果我将total_trucks和total_capacity添加到serializer中,它将抛出一个关于这些字段在模型上不存在的错误。
选项2可以通过使用View而不是serializer来工作,但如果模型包含很多字段,而只有一部分字段需要在JSON中,那么在不使用serializer的情况下构建端点将是一个相当丑陋的hack。