Django如何返回一对多关联数据?附模型类及序列化器代码
在Django REST Framework中返回一对多关联数据的方案
针对你定义的plans(主表)和plan_cat(从表,外键关联plans)的一对多关系,下面几种实用方法可以帮你在序列化时返回关联的所有plan_cat数据:
方法1:嵌套序列化器(最常用、最灵活)
先定义plan_cat的序列化器,再在plans的序列化器中嵌套它,就能把每个套餐对应的所有分类一起返回:
from rest_framework import serializers from .models import plans, plan_cat # 先定义从表的序列化器 class PlanCatSerializer(serializers.ModelSerializer): class Meta: model = plan_cat fields = ['id', 'cat_name', 'cat_is_active'] # 主表序列化器,嵌套关联的分类序列化器 class PlanSerializer(serializers.ModelSerializer): # 这里的`plan_cat_set`是Django默认的反向关联名称(模型名小写+_set) # 如果你的外键字段定义了related_name,就替换成你设置的名称 plan_cats = PlanCatSerializer(source='plan_cat_set', many=True, read_only=True) class Meta: model = plans fields = ['id', 'plan_name', 'plan_price', 'plan_is_active', 'plan_cats']
序列化后返回的格式大概是这样:
{ "id": 1, "plan_name": "基础套餐", "plan_price": 99, "plan_is_active": true, "plan_cats": [ {"id": 1, "cat_name": "基础服务", "cat_is_active": true}, {"id": 2, "cat_name": "售后支持", "cat_is_active": true} ] }
方法2:用depth参数快速实现嵌套
如果只是想简单返回关联模型的所有字段,不想单独写嵌套序列化器,可以用depth参数自动递归序列化关联数据:
class PlanSerializer(serializers.ModelSerializer): class Meta: model = plans fields = ['id', 'plan_name', 'plan_price', 'plan_is_active', 'plan_cat_set'] depth = 1 # 指定序列化1层关联数据
这种方法适合快速测试或简单场景,但灵活性差,没法自定义关联字段的返回内容。
方法3:SerializerMethodField自定义返回逻辑
如果需要对关联数据做额外处理(比如只返回活跃的分类),可以用这个方法定制返回逻辑:
class PlanSerializer(serializers.ModelSerializer): active_plan_cats = serializers.SerializerMethodField() class Meta: model = plans fields = ['id', 'plan_name', 'plan_price', 'plan_is_active', 'active_plan_cats'] def get_active_plan_cats(self, obj): # 过滤出仅活跃的分类并序列化 active_cats = obj.plan_cat_set.filter(cat_is_active=True) return PlanCatSerializer(active_cats, many=True).data
额外性能优化提示
如果数据量较大,记得在视图中用prefetch_related避免N+1查询问题:
from rest_framework import generics from .models import plans from .serializers import PlanSerializer class PlanList(generics.ListAPIView): queryset = plans.objects.prefetch_related('plan_cat_set').all() serializer_class = PlanSerializer
另外提个小建议:把模型名改成大驼峰格式(比如Plan代替plans,PlanCategory代替plan_cat),这是Python和Django的通用命名规范,代码会更易读~
内容的提问来源于stack exchange,提问作者msd
相关产品推荐
相关产品推荐

