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
相关产品推荐
相关产品推荐

