我正在尝试查看Django REST Framework序列化程序中的嵌套注释(聚合/计算)字段。这将允许使用带注释的字段更干净地工作。这篇文章类似于Aggregate (and other annotated) fields in Django Rest Framework serializers但是我想要一种类似的技术来嵌套。下面的方法可以看出它如何在没有嵌套的情况下工作,以及它如何与嵌套无关。
我知道这可以通过手动(使用Django View)或使用重载我不感兴趣的数据库的方法来实现。但也许有一个高效且优雅的解决方案来解决这个问题。
以下作品(非嵌套)
模型
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'.
答案 0 :(得分:6)
作为参考,还可以在模型IceCreamTruck
上注释每辆卡车的驱动程序数量,例如使用自定义管理器:
class AnnotatedManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(amount_of_drivers=Count('drivers'))
class IceCreamTruck(models.Model):
company = models.ForeignKey('IceCreamCompany', related_name='trucks')
capacity = models.IntegerField()
objects = AnnotatedManager()
然后您无需为视图集添加注释,因为amount_of_drivers
上已注释trucks
:
class IceCreamCompanyViewSet(viewsets.ModelViewSet):
queryset = IceCreamCompany.objects.prefetch_related('trucks', 'trucks__drivers').all()
serializer_class = IceCreamCompanySerializer
它应该比在序列化器内部计数更有效。
答案 1 :(得分:1)
我得到了一个答案,使用Django REST谷歌小组在IntegerField中使用read_only = True,这有助于消除错误,但之后该字段不再显示。也许我的注释是错误的。无论如何,我最终在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(它在代码本身中可见)但我没有选择它所以我没有&#39 ; t必须修改我的模型太多。这也会造成太多疑问。