【发布时间】:2015-11-02 10:39:18
【问题描述】:
我正在尝试找出添加注释字段的最佳方法,例如将任何聚合(计算)字段添加到 DRF(模型)序列化器。我的用例只是端点返回的字段未存储在数据库中而是从数据库中计算出来的情况。
我们看下面的例子:
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()
序列化器.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']
序列化器.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')
上面的代码也许可以重构一下,但它不会改变这个选项将执行 2 个额外的 SQL 查询的事实每个 IceCreamCompany 这不是很有效。
选项 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 查询中获取聚合字段,但我不确定如何将它们添加到序列化程序,因为 DRF 并不神奇地知道我已经在 QuerySet 中注释了这些字段。如果我将 total_trucks 和 total_capacity 添加到序列化程序,它会抛出关于模型上不存在这些字段的错误。
选项 2 可以通过使用 View 在没有序列化程序的情况下工作,但如果模型包含很多字段,并且只有一些字段需要在 JSON 中,那么构建端点将是一个有点丑陋的黑客攻击没有序列化器。
【问题讨论】:
标签: django python-3.x django-rest-framework