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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 15:43:23