如何在Django子序列化器中获取父模型ID?
解决Django嵌套序列化器中子序列化器获取父模型ID的问题
要在嵌套保存Parent和关联Material时自动关联父模型ID,不需要在子序列化器MaterialSerializer中手动处理,只需重写父序列化器ParentSerializer的create方法,手动创建关联关系即可:
步骤1:调整MaterialSerializer
去掉parent字段(或设置为只读),因为我们不需要从前端接收父ID,而是由后端自动关联:
class MaterialSerializer(serializers.ModelSerializer): class Meta: model = Material fields = ['id', 'name', 'description'] # 如果需要在返回数据中包含parent字段,添加以下配置: # fields = ['id', 'name', 'description', 'parent'] # extra_kwargs = {'parent': {'read_only': True}}
步骤2:重写ParentSerializer的create方法
在父序列化器中先创建Parent实例,再遍历嵌套的Material数据并关联到该父实例:
class ParentSerializer(serializers.ModelSerializer): material = MaterialSerializer(many=True) class Meta: model = Parent fields = ['name', 'date', 'material'] def create(self, validated_data): # 提取嵌套的Material数据 materials_data = validated_data.pop('material') # 创建Parent主实例 parent = Parent.objects.create(**validated_data) # 批量创建关联的Material,自动绑定parent_id for material_data in materials_data: Material.objects.create(parent=parent, **material_data) return parent
补充:如果需要在子序列化器中访问父实例(如验证逻辑)
如果你的业务需要在MaterialSerializer中基于父模型做验证或其他逻辑,可以通过context传递父实例。比如在父序列化器的update方法中(此时父实例已存在):
class ParentSerializer(serializers.ModelSerializer): material = MaterialSerializer(many=True) def update(self, instance, validated_data): materials_data = validated_data.pop('material') # 将父实例传入子序列化器的context for material_data in materials_data: serializer = MaterialSerializer(data=material_data, context={'parent': instance}) serializer.is_valid(raise_exception=True) serializer.save(parent=instance) # 更新父实例字段 instance.name = validated_data.get('name', instance.name) instance.date = validated_data.get('date', instance.date) instance.save() return instance
然后在MaterialSerializer中可以通过self.context.get('parent')获取父实例:
class MaterialSerializer(serializers.ModelSerializer): class Meta: model = Material fields = ['id', 'name', 'description', 'parent'] def validate_name(self, value): parent = self.context.get('parent') # 基于父实例做验证逻辑,比如检查同名Material是否存在 if Material.objects.filter(parent=parent, name=value).exists(): raise serializers.ValidationError(f"该父项已存在名为{value}的物料") return value
内容的提问来源于stack exchange,提问作者Justscoundrel
相关产品推荐
相关产品推荐

