Django DRF嵌套序列化程序-筛选子序列化程序上的数据

Django DRF嵌套序列化程序-筛选子序列化程序上的数据,django,serialization,django-rest-framework,Django,Serialization,Django Rest Framework,我正在尝试使用嵌套序列化程序。如何使用根序列化程序过滤孙子序列化程序上的数据 学校和课程有多对多的关系,因此任何学校都可以订阅任何课程。每所学校都有班级,这些班级是一个项目的一部分,这就是为什么PClass有学校和项目的外键 当我调用我的api…/api/school/1时,我想得到学校订阅的所有程序以及每个程序中(该学校)有哪些课程 班级学校(TimestamesedModel,SoftDeletableModel): name=models.CharField(最大长度=40) slug=m

我正在尝试使用嵌套序列化程序。如何使用根序列化程序过滤孙子序列化程序上的数据

学校和课程有多对多的关系,因此任何学校都可以订阅任何课程。每所学校都有班级,这些班级是一个项目的一部分,这就是为什么PClass有学校和项目的外键

当我调用我的api…/api/school/1时,我想得到学校订阅的所有程序以及每个程序中(该学校)有哪些课程

班级学校(TimestamesedModel,SoftDeletableModel):
name=models.CharField(最大长度=40)
slug=models.SlugField(最大长度=40,默认值=“”,空白值=True)
类程序(TimeStampedModel、SoftDeletableModel):
name=models.CharField(最大长度=50,唯一性=True)
slug=models.SlugField(最大长度=50,默认值=“”,空白值=True,唯一值=True)
description=models.CharField(最大长度=100,空白=True)
school=models.ForeignKey(school,blank=True,null=True,related_name=“programs”)
类PClass(TimeStampedModel,SoftDeletableModel):
name=models.CharField(最大长度=50)
slug=models.SlugField(最大长度=50,默认值=“”,空白值=True)
description=models.CharField(最大长度=100)
program=models.ForeignKey(program,related_name=“classes”)
学校=模型。外键(学校,相关的_name=“类”)
和以下序列化程序:

类序列化程序(serializers.ModelSerializer):
programs=ProgramSerializer(source='get\u programas',many=True,read\u only=True)
类元:
模型=学校
字段='\uuuu所有\uuuu'
查找_字段='slug'
额外费用={
'url':{'lookup_field':'slug'}
}
类PClassSerializer(serializers.ModelSerializer):
类元:
模型=类
字段=('name','slug')
类ProgramSerializer(serializers.ModelSerializer):
school=serializers.SlugRelatedField(queryset=school.objects.all(),
slug_field='name',
必需=错误)
classes=PClassSerializer(many=True,read_only=True)
类元:
模型=程序
排除=('id',)
查找_字段='slug'
额外费用={
'url':{'lookup_field':'slug'}
}

这可能吗?还是我设置模型的方式有问题?

我知道有两种方法可以做到这一点。首先,你已经很接近了 编辑:注意到您正在使用相关的名称。我已经更新了答案

class SchoolSerializer( serializers.ModelSerializer):
    programas = ProgramSerializer(source='programs',many=True,read_only=True)
对于更复杂的过滤,最好的方法是使用字段。这里有一个例子

您可能还希望在视图中进行一些预取,以获取queryset,从而最小化查询的数量

class SchoolSerializer(serializers.ModelSerializer):
    programas = SerializerMethodField(source='get_programas',many=True,read_only=True)
    class Meta:
        model = Unidade
        fields = '__all__'
        lookup_field = 'slug'
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

    def get_programas(self, obj):
        # You can do more complex filtering stuff here.
        return ProgramaSerializer(obj.programs.all(), many=True, read_only=True).data
要获得PClasses,您只需使用它筛选查询集

program.classes.filter(school=program.school)
ProgramSerializer的完整示例如下

class ProgramSerializer(serializers.ModelSerializer):
    classes = SerializerMethodField(source='get_classes', many=True, read_only=True)
    class Meta:
        model = Program

    def get_classes(self, obj):
        return PClassSerializer(obj.classes.filter(school=obj.school), many=True, read_only=True).data
编辑10个左右:

由于您已将课程->学校从foreignkey更改为许多,这将改变一切

对于schoolserializer,需要使用SerializerMethodField。通过这种方式,您可以向嵌套序列化程序传递额外的数据

class SchoolSerializer(serializers.ModelSerializer):
    classes = SerializerMethodField(source='get_programs')
    class Meta:
        model = School

    def get_programs(self, obj):
        return ProgramSerializer(obj.program_set.all(), many=True, read_only=True, context={ "school": obj }).data

class ProgramSerializer(serializers.ModelSerializer):
    classes = SerializerMethodField(source='get_classes', many=True, read_only=True)
    class Meta:
        model = Program

    def get_classes(self, obj):
        return PClassSerializer(obj.classes.filter(school=self.context["school"]), many=True, read_only=True).data

如何让PClassSerializer仅显示正在SchoolSerializer上序列化的学校的班级?刚刚添加到我的答案的底部。但是program.School将返回一个列表,其中包含此计划中注册的所有学校,不是吗?或者我遗漏了什么?我应该把program.pclass_set.filter(school=program.school)放在哪里对不起,需要更多关于这个的细节。。。花了一下午的时间研究之后,我有点迷路了……Django编程的一个一般提示是,除非必要,否则不要使用相关的\u名称,因为其他人只使用默认的\u集语法更容易。刚刚注意到所有相关的_名称,并更新了答案以使用正确的参考资料