如何在Django REST中通过外键从多表提取返回关联数据?
问题描述
我有如下模型:
class Stock(models.Model): bar_id = models.ForeignKey(Bar, on_delete=models.CASCADE, related_name="bars") stock = models.IntegerField() class Bar(models.Model): name = models.CharField(max_length=200)
注意一个Bar可以对应多个Stock。我希望获取并返回指定Bar关联的所有Stock数据。
目前我的URL配置如下:
path('stock/<int:pk>/', views.StockListPerBar.as_view())
对应的视图为:
class StockListPerBar(generics.RetrieveAPIView): queryset = Bar.objects.all() serializer_class = StockListPerBarSerializer
序列化器为:
class StockListPerBarSerializer(serializers.ModelSerializer): bars = serializers.PrimaryKeyRelatedField(many=True, read_only=True) class Meta: model = Bar fields = ["name", "bars"]
当前输出结果为:
{ "name": "Some bar name", "bars": [ 4, 5, 6, 7 ] }
但我期望的输出格式如下(截断示例):
[ { "id": 4, "stock": 10 }, { "id": 5, "stock": 0 } ]
请问该如何实现?
解决方案
你当前的核心问题是视图和序列化器都围绕Bar对象展开,但实际需要返回的是Stock对象列表,调整以下三个部分即可实现需求:
1. 优化模型关联名(可选但推荐)
当前Stock的bar_id字段用related_name="bars"容易混淆(实际关联的是Stock列表),建议改成更清晰的命名:
class Stock(models.Model): bar_id = models.ForeignKey(Bar, on_delete=models.CASCADE, related_name="stocks") # 修改为stocks stock = models.IntegerField()
如果不想修改,后续代码中保持用bars即可。
2. 编写Stock专用序列化器
需要一个专门序列化Stock对象的序列化器,匹配你期望的输出字段:
class StockSerializer(serializers.ModelSerializer): class Meta: model = Stock fields = ["id", "stock"]
3. 修改视图类
把RetrieveAPIView换成ListAPIView(因为要返回列表数据),并根据URL传入的Bar ID过滤Stock:
class StockListPerBar(generics.ListAPIView): serializer_class = StockSerializer def get_queryset(self): # 从URL参数获取Bar的ID,过滤对应的Stock bar_pk = self.kwargs.get('pk') return Stock.objects.filter(bar_id__pk=bar_pk)
也可以通过Bar对象反向关联获取(适合已修改related_name的场景):
def get_queryset(self): bar = Bar.objects.get(pk=self.kwargs.get('pk')) return bar.stocks.all() # 未修改related_name则用bar.bars.all()
4. 验证结果
现在访问/stock/<bar_id>/就会返回你期望的JSON数组格式:
[ { "id": 4, "stock": 10 }, { "id": 5, "stock": 0 } ]
原写法问题说明
原来的视图用RetrieveAPIView会返回单个Bar对象,序列化器仅能列出关联Stock的ID,而你需要的是Stock对象的完整列表,因此核心是将视图的查询目标从Bar切换为Stock,并过滤出指定Bar下的Stock数据。
内容的提问来源于stack exchange,提问作者Itération 122442
相关产品推荐
相关产品推荐

