我試圖找出添加注釋字段的最佳方法,例如任何聚合(計算)字段到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')
上面的代碼可能被重構了一點,但是它不會改變這個事實,這個選項將對IceCream公司執行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添加到序列化程序中,那么它將拋出一個關於模型中不存在的這些字段的錯誤.
選項2可以通過使用View而不使用串行器來實現,但是如果模型包含很多字段,並且只有一些需要在JSON中,那么在沒有串行器的情況下構建端點將是一個有些丑陋的攻擊.
可能的解決方案:
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') )
serializers.py
class IceCreamCompanySerializer(serializers.ModelSerializer): total_trucks = serializers.IntegerField() total_capacity = serializers.IntegerField() class Meta: model = IceCreamCompany fields = ('name', 'total_trucks', 'total_capacity')
通過使用Serializer fields我有一個小例子上班.這些字段必須聲明為序列化程序的類屬性,因此DRF不會在IceCreamCompany模型中拋出不存在的錯誤.
