django之DRF 嵌套序列化器之过滤子序列化器上的数据

findumars 阅读:133 2025-06-02 22:19:02 评论:0

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

学校和项目之间存在多对多关系,因此任何学校都可以订阅任何项目。每所学校都有类(class),这些类(class)是程序的一部分,这就是为什么 PClass 有学校和程序的外键。

当我调用我的 api .../api/school/1 我想获得学校订阅的所有程序以及每个程序中的哪些类(class)(在该学校)

class School(TimeStampedModel, SoftDeletableModel): 
    name = models.CharField(max_length=40) 
    slug = models.SlugField(max_length=40, default='', blank=True) 
 
class Program(TimeStampedModel, SoftDeletableModel): 
    name = models.CharField(max_length=50, unique=True) 
    slug = models.SlugField(max_length=50,default='',blank=True, unique=True) 
    description = models.CharField(max_length=100, blank=True) 
    school = models.ForeignKey(School, blank=True, null=True, related_name="programs") 
 
class PClass(TimeStampedModel, SoftDeletableModel): 
    name = models.CharField(max_length=50) 
    slug = models.SlugField(max_length=50,default='',blank=True) 
    description = models.CharField(max_length=100) 
    program = models.ForeignKey(Program, related_name="classes") 
    school = models.ForeignKey(School, related_name="classes") 

以及以下序列化程序:

class SchoolSerializer( serializers.ModelSerializer): 
    programs = ProgramSerializer(source='get_programas',many=True,read_only=True) 
    class Meta: 
        model = School 
        fields = '__all__' 
        lookup_field = 'slug' 
        extra_kwargs = { 
            'url': {'lookup_field': 'slug'} 
        } 
 
class PClassSerializer(serializers.ModelSerializer): 
    class Meta: 
        model = Class 
        fields = ('name','slug') 
 
class ProgramSerializer(serializers.ModelSerializer): 
    school = serializers.SlugRelatedField(queryset=School.objects.all(), 
                                            slug_field='name', 
                                            required=False) 
    classes = PClassSerializer(many=True,read_only=True) 
    class Meta: 
        model = Program 
        exclude = ('id',) 
        lookup_field = 'slug' 
        extra_kwargs = { 
            'url': {'lookup_field': 'slug'} 
        } 

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

请您参考如下方法:

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

class SchoolSerializer( serializers.ModelSerializer): 
    programas = ProgramSerializer(source='programs',many=True,read_only=True) 

对于更复杂的过滤,最好的方法是使用 SerializerMethodField field 。这是一个例子。

您可能还希望在 View 中进行一些预取以获取查询集以最小化查询数量。
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 个左右:

由于您已将程序 -> 学校从外键更改为多对多,这会改变一切。

对于schoolserializer,您需要使用SerializerMethodField。这样你就可以传入额外的 context到您的嵌套序列化程序。
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 


标签:Django
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号