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

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

解决AttributeError:int实例无code属性的问题

问题根源

你遇到的这个错误,本质是查询集返回的country字段是整数ID,而非Country模型实例,但你的序列化器却期望用CountrySerializers去序列化它,自然会报错“int实例没有code属性”。

具体来说,你的get_queryset方法里用了values('country'),这个方法会返回字典格式的查询结果,其中country对应的是关联模型的主键ID(整数类型),而不是完整的Country对象。但TradeAggregateSerializers里的country = CountrySerializers(read_only=True),是要序列化一个Country实例去读取它的code、name字段,两者不匹配就触发了错误。

解决方案:调整查询逻辑与序列化器

我们可以换一种思路,从Country模型出发反向聚合关联的Trade数据,这样既能获取完整的国家信息,又能计算指定字段的平均值。

1. 修改视图类的查询逻辑

把查询集从Trade转向Country,通过反向关联(trade__前缀)来计算平均值,同时做参数校验避免非法输入:

from rest_framework import serializers

class TradeAggragateViewSet(viewsets.ModelViewSet):
    queryset = Country.objects.all()  # 改为Country的查询集
    serializer_class = TradeAggregateSerializers

    def get_queryset(self):
        import_or_export = self.request.GET.get('data_type')
        # 校验参数合法性
        if import_or_export not in ['imports', 'exports']:
            raise serializers.ValidationError("data_type must be 'imports' or 'exports'")
        # 为每个国家标注指定字段的平均值
        queryset = self.queryset.annotate(
            value=models.Avg(f'trade__{import_or_export}')
        )
        return queryset

2. 调整序列化器适配新的查询集

现在查询集是Country实例,所以序列化器可以直接继承CountrySerializers,新增value字段即可:

class TradeAggregateSerializers(CountrySerializers):
    value = serializers.DecimalField(max_digits=10, decimal_places=2)

    class Meta(CountrySerializers.Meta):
        fields = CountrySerializers.Meta.fields + ('value',)

为什么这个方案可行?

  • 从Country模型出发查询,每个结果都是完整的Country实例,CountrySerializers可以正常序列化它的code、name字段;
  • 通过annotate和反向关联trade__{import_or_export},直接计算出每个国家对应贸易字段的平均值,无需额外处理;
  • 参数校验能避免传入非法字段导致的后续错误。

另一种可选方案(不修改查询模型)

如果你坚持从Trade模型查询,可以调整values的返回字段,包含国家的所有属性,然后修改序列化器对应这些字段:

# 视图类的get_queryset
def get_queryset(self):
    import_or_export = self.request.GET.get('data_type')
    if import_or_export not in ['imports', 'exports']:
        raise serializers.ValidationError("data_type must be 'imports' or 'exports'")
    queryset = Trade.objects.values(
        'country__id', 'country__code', 'country__name'
    ).annotate(value=models.Avg(import_or_export))
    return queryset

# 对应的序列化器
class TradeAggregateSerializers(serializers.Serializer):
    country = serializers.DictField(
        child=serializers.CharField(),
        source='*'  # 把country__开头的字段映射为字典
    )
    value = serializers.DecimalField(max_digits=10, decimal_places=2)

    def to_representation(self, instance):
        # 手动把country__code、country__name整理为country字典
        return {
            'country': {
                'id': instance['country__id'],
                'code': instance['country__code'],
                'name': instance['country__name']
            },
            'value': instance['value']
        }

不过这个方案需要手动处理字段映射,不如第一种方案简洁优雅。

内容的提问来源于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:04:06