我正在尝试使用嵌套的序列化程序。如何使用根序列化器过滤孙子串行器上的数据?
学校和课程有很多关系所以任何学校都可以订阅任何课程。每所学校都有课程,这些课程是课程的一部分,这就是PClass为学校和课程提供外键的原因。
当我打电话给我的api ... / api / school / 1时,我希望获得学校订阅的所有课程以及每个课程(在该学校中)可用的课程
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'}
}
这可能吗?或者我设置模型的方式有问题吗?
答案 0 :(得分:4)
我知道如何做到这两种方式。首先,你已经非常接近了 编辑:注意到您正在使用相关名称。我已经更新了
的答案class SchoolSerializer( serializers.ModelSerializer):
programas = ProgramSerializer(source='programs',many=True,read_only=True)
对于更复杂的过滤,最好的方法是使用SerializerMethodField字段。这是一个例子。
您可能还希望在视图中进行一些预取,以使查询集最小化查询次数。
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到ManyToMany的学校,这改变了一切。
对于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