在Django REST Framework序列化器中嵌套注释字段
问题描述:
我想在Django REST Framework序列化器中查看嵌套注释(聚合/计算)字段。这将允许使用带注释的字段更干净地工作。这篇文章类似于Aggregate (and other annotated) fields in Django Rest Framework serializers但是我想要一个类似的技术来嵌套工作。下面的方法是可见的,如何在没有嵌套的情况下工作,以及它如何看起来不适用于嵌套。在Django REST Framework序列化器中嵌套注释字段
我知道这可以通过手动(使用Django视图)或使用重载数据库的方法来实现,但我可能对此问题有一个表现优雅的解决方案。
以下作品(未嵌套)
模型
class IceCreamCompany(models.Model):
name = models.CharField(max_length=255)
class IceCreamTruck(models.Model):
company = models.ForeignKey('IceCreamCompany', related_name='trucks')
capacity = models.IntegerField()
class IceCreamTruckDriver(models.Model):
name = models.CharField(max_length=255)
first_name = models.CharField(max_length=255)
truck = models.ForeignKey('IceCreamTruck', related_name='drivers')
串行器
class IceCreamTruckDriverSerializer(serializers.ModelSerializer):
class Meta:
model = IceCreamTruckDriver
fields = ('name', 'first_name')
class IceCreamTruckSerializer(serializers.ModelSerializer):
drivers = IceCreamTruckDriverSerializer(many=True, read_only=True)
class Meta:
model = IceCreamTruck
fields = ('capacity', 'drivers')
class IceCreamCompanySerializer(serializers.ModelSerializer):
trucks = IceCreamTruckSerializer(many=True, read_only=True)
amount_of_trucks = serializers.IntegerField()
class Meta:
model = IceCreamCompany
fields = ('name', 'trucks', 'amount_of_trucks')
视图集
class IceCreamCompanyViewSet(viewsets.ModelViewSet):
queryset = IceCreamCompany.objects.prefetch_related('trucks', 'trucks__drivers')\
.annotate(amount_of_trucks=Count('trucks'))\
.all()
serializer_class = IceCreamCompanySerializer
结果
"results": [
{
"name": "Pete Ice Cream",
"trucks": [
{
"capacity": 35,
"drivers": [
{
"name": "Damian",
"first_name": "Ashley"
},
{
"name": "Wilfrid",
"first_name": "Lesley"
}
]
},
{
"capacity": 30,
"drivers": [
{
"name": "Stevens",
"first_name": "Joseph"
}
]
},
{
"capacity": 30,
"drivers": []
}
],
"amount_of_trucks": 3
}
]
下不工作(嵌套)
同款
串行器
class IceCreamTruckDriverSerializer(serializers.ModelSerializer):
class Meta:
model = IceCreamTruckDriver
fields = ('name', 'first_name')
class IceCreamTruckSerializer(serializers.ModelSerializer):
drivers = IceCreamTruckDriverSerializer(many=True, read_only=True)
amount_of_drivers = serializers.IntegerField()
class Meta:
model = IceCreamTruck
fields = ('capacity', 'drivers', 'amount_of_drivers')
class IceCreamCompanySerializer(serializers.ModelSerializer):
trucks = IceCreamTruckSerializer(many=True, read_only=True)
class Meta:
model = IceCreamCompany
fields = ('name', 'trucks')
视图集中
class IceCreamCompanyViewSet(viewsets.ModelViewSet):
queryset = IceCreamCompany.objects.prefetch_related('trucks', 'trucks__drivers')\
.annotate(trucks__amount_of_drivers=Count('trucks__drivers'))\
.all()
serializer_class = IceCreamCompanySerializer
结果
AttributeError at /ice/
Got AttributeError when attempting to get a value for field `amount_of_drivers` on serializer `IceCreamTruckSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `IceCreamTruck` instance.
Original exception text was: 'IceCreamTruck' object has no attribute 'amount_of_drivers'.
答
我使用Django的REST谷歌群体使用IntegerField,这有助于消除误差内READ_ONLY =真答案但之后该字段不再显示。也许我的注释是错误的。无论如何,我最终在Django中使用自定义视图,因为我最终需要更多的数据。但是,您可以通过其他方式获取数据:
一个非常优雅的解决方案是删除注释函数并使用可以给我我的结果的SerializerMethodField。
然而:这确实会造成很多查询!
同款
串行器
class IceCreamTruckDriverSerializer(serializers.ModelSerializer):
class Meta:
model = IceCreamTruckDriver
fields = ('name', 'first_name')
class IceCreamTruckSerializer(serializers.ModelSerializer):
drivers = IceCreamTruckDriverSerializer(many=True, read_only=True)
amount_of_drivers = serializers.SerializerMethodField()
def get_amount_of_drivers(self, obj):
return obj.drivers.count()
class Meta:
model = IceCreamTruck
fields = ('capacity', 'drivers', 'amount_of_drivers')
class IceCreamCompanySerializer(serializers.ModelSerializer):
trucks = IceCreamTruckSerializer(many=True, read_only=True)
class Meta:
model = IceCreamCompany
fields = ('name', 'trucks')
视图集中
class IceCreamCompanyViewSet(viewsets.ModelViewSet):
queryset = IceCreamCompany.objects.prefetch_related('trucks', 'trucks__drivers').all()
serializer_class = IceCreamCompanySerializer
结果
"results": [
{
"name": "Pete Ice Cream",
"trucks": [
{
"capacity": 35,
"drivers": [
{
"name": "Damian",
"first_name": "Ashley"
},
{
"name": "Wilfrid",
"first_name": "Lesley"
}
],
"amount_of_drivers": 2
},
{
"capacity": 30,
"drivers": [
{
"name": "Stevens",
"first_name": "Joseph"
}
],
"amount_of_drivers": 1
},
{
"capacity": 30,
"drivers": [],
"amount_of_drivers": 0
}
]
}
]
它也可以使用这样的模式里面功能:Django Rest Framework Ordering on a SerializerMethodField(它在代码本身可见的),但我没有选择它,所以我没有太多的修改我的模型。这也会造成太多的查询。
难道你不应该将这个字段命名为amount_of_drivers而不是trucks__amount_of_drivers吗? – Roba
如果我在查询集中的annotate函数中使用了amount_of_drivers,它会尝试在IceCreamCompanySerializer中查找amount_of_drivers字段,该字段不会是嵌套的注释字段。我希望它可以在IceCreamTruckSerializer中使用。 – Robin
不,先生,我只是建议重命名注释:.annotate(amount_of_drivers = Count('trucks__drivers'));该错误将此问题命名为查询集中未找到注释列的名称。注释列的名字只是一个名字,不会为你穿越关系。 – Roba