You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django分组嵌套序列化器聚合报错:int对象无code属性

解决嵌套序列化器聚合时的AttributeError问题

嘿,我来帮你搞定这个报错!你遇到的AttributeError本质原因是查询返回的数据格式和序列化器期望的不匹配,具体来说:

你的get_queryset方法里用了Trade.objects.values('country').annotate(...),这个写法返回的是一组字典,其中country字段的值是国家的ID(整数类型),而不是完整的Country模型实例。但你的TradeAggregateSerializers里的country字段用的是CountrySerializers,它需要接收一个Country对象才能序列化出code、name等字段,面对整数ID自然就会报错说“int对象没有code属性”。

下面给你两种解决方案,优先推荐第一种(性能更优):

方案一:从Country模型入手做聚合(推荐)

这种方式直接从Country模型出发,关联Trade表完成聚合查询,返回的是完整的Country实例,完美适配嵌套序列化器。

1. 修改序列化器

新增一个继承自CountrySerializers的序列化器,添加聚合结果字段:

class CountryWithAggregateSerializer(CountrySerializers):
    # 字段参数和Trade里的decimal字段匹配
    value = serializers.DecimalField(max_digits=15, decimal_places=2, read_only=True)

    class Meta(CountrySerializers.Meta):
        # 保留原有的国家字段,新增value字段
        fields = CountrySerializers.Meta.fields + ('value',)

2. 调整视图逻辑

修改视图的查询集,从Country模型做聚合,同时增加参数合法性校验:

class TradeAggragateViewSet(viewsets.ModelViewSet):
    queryset = Country.objects.all()
    serializer_class = CountryWithAggregateSerializer

    def get_queryset(self):
        data_type = self.request.GET.get('data_type')
        # 验证传入的参数是否合法,避免非法字段或SQL注入风险
        allowed_fields = ['imports', 'exports']
        if data_type not in allowed_fields:
            # 可以返回空查询集,或者抛出400 Bad Request错误
            return Country.objects.none()
        
        # 关联Trade表,动态指定聚合字段,计算平均值
        queryset = Country.objects.annotate(
            value=models.Avg(f'trade__{data_type}')
        ).filter(value__isnull=False)  # 过滤掉没有贸易数据的国家(可选)
        return queryset

方案二:修改序列化器适配字典数据(不推荐,有N+1查询问题)

如果你坚持要从Trade模型查询,可以用SerializerMethodField手动根据ID获取国家信息,但这种方式会触发N+1查询(每个国家单独查一次数据库),性能较差:

class TradeAggregateSerializers(serializers.ModelSerializer):
    country = serializers.SerializerMethodField()
    value = serializers.DecimalField(max_digits=15, decimal_places=2)

    def get_country(self, obj):
        # obj是values返回的字典,obj['country']是国家ID
        country = Country.objects.get(id=obj['country'])
        return CountrySerializers(country).data

    class Meta:
        model = Trade
        fields = ('country','value')

额外提醒

  • 一定要做参数合法性校验,避免用户传入imports/exports之外的字段,防止错误或安全问题。
  • 方案一中的filter(value__isnull=False)可以过滤掉没有任何贸易记录的国家,如果你需要保留这些国家(value为null),可以去掉这个过滤条件。

内容的提问来源于stack exchange,提问作者Hassam.C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:03:16