You need to enable JavaScript to run this app. DRF使用ForeignKey Serializer按Campaign展示关联Product列表遇报错
优惠活动
大模型
产品
解决方案
定价
更多

DRF使用ForeignKey Serializer按Campaign展示关联Product列表遇报错

错误根因梳理
  • 序列化器与传入对象不匹配:CampaignProductsSerializer是绑定Campaign模型的序列化器,但视图中传入的是Product类型的查询集,且额外加了many=True参数,会对每一个Product实例执行Campaign的序列化规则,自然会触发'Product' object has no attribute 'products'报错——反向关联products是Campaign模型的专属属性,Product实例本身不存在这个字段。
  • 关联字段配置缺失:原序列化器中只写了PrimaryKeyRelatedField(read_only=True, many=True),既没有指定关联的查询集范围,也没有配置成嵌套序列化结构,就算匹配上模型,最终输出的也只会是无意义的产品ID列表,不是完整的产品信息。
  • 视图逻辑偏离目标:原视图的逻辑是筛选出所有属于对应campaign的Product,完全跳过了“以Campaign为主体、挂载关联产品列表”的需求,和序列化器的设计目标完全错位。
正确实现流程

1. 配置嵌套序列化结构

先单独定义Product的基础序列化器,用来输出产品的完整字段,作为嵌套结构的子级:

class ProductBaseSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        # 按需调整需要返回的产品字段
        fields = ['id', 'title', 'image', 'market_price', 'selling_price', 'description']

修改CampaignProductsSerializer,利用模型上已经配置好的related_name="products"反向关联,直接嵌入产品序列化器:

class CampaignProductsSerializer(serializers.ModelSerializer):
    # 匹配模型上的反向关联products,many=True表示是一对多的关联关系
    products = ProductBaseSerializer(many=True, read_only=True)
    class Meta:
        model = Campaign
        fields = ['id', 'title', 'img', 'products']

注意:不需要额外手写PrimaryKeyRelatedField,DRF会自动匹配反向关联的查询集。如果只需要输出产品的主键ID列表,只需要把products字段替换为products = serializers.PrimaryKeyRelatedField(many=True, read_only=True)即可。

2. 修正视图查询逻辑

要实现以Campaign为主体的返回,就需要根据URL传入的campaign id取到对应的Campaign实例,再传给对应的序列化器,不需要添加many=True参数:

from django.shortcuts import get_object_or_404

class CampaignProducts(APIView):
    def get(self, request, id):
        # 预加载关联的产品列表,避免数据库多次查询
        campaign = get_object_or_404(
            Campaign.objects.prefetch_related('products'),
            id=id
        )
        serializer = CampaignProductsSerializer(campaign)
        return Response(serializer.data)

用get_object_or_404替代全量查询Campaign的逻辑,当传入的id不存在时会自动返回404响应,无需额外写异常判断;搭配prefetch_related('products')可以把关联的产品数据一次性查出来,避免循环查询拖慢接口性能。

3. 最终返回结构示例

调整完成后,接口会返回单条Campaign的完整信息,同时在products字段下挂载所有关联的Product列表,结构参考:

{
  "id": 1,
  "title": "年中大促活动",
  "img": "campaign/midyear-sale.jpg",
  "products": [
    {
      "id": 12,
      "title": "蓝牙耳机",
      "image": "products/earphone.jpg",
      "market_price": 399,
      "selling_price": 199,
      "description": "主动降噪 30小时续航"
    },
    {
      "id": 15,
      "title": "机械键盘",
      "image": "products/keyboard.jpg",
      "market_price": 599,
      "selling_price": 299,
      "description": "全键热插拔 三模连接"
    }
  ]
}

内容的提问来源于stack exchange,提问作者Md. Sakibur Rahman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 20:57:05