Django REST Framework保存嵌套的序列化程序而不创建它们

时间:2014-08-11 21:56:07

标签: python json django serialization django-rest-framework

我有一个像这样的序列化器:

class DataSetColumnSerializer(serializers.ModelSerializer):
    custom_target = target_serializers.CustomTargetSerializer()

    class Meta:
        model = dataset_models.DataSetColumn

custom_target使用以下序列化程序:

class CustomTargetSerializer(serializers.ModelSerializer):
    class Meta:
        model = target_models.CustomTarget

我正在传回一个对象,其中包含我要为custom_target设置的DataSetColumn。当我验证序列化程序并保存它时:

serializer = serializers.DataSetColumnSerializer(column, data=request.DATA)

if serializer.is_valid():
    serializer.save()

custom_target序列化程序正在创建新的CustomTarget,而不是仅将custom_target的{​​{1}}设置为传入的对象。我尝试设置{{1}只读。这是因为它不会创建新的DataSetColumn,但也不会将CustomTargetSerializer设置为对象。

如何在序列化CustomTarget对象上使用custom_targetserializer.save()设置为传入的嵌套对象,而不是从嵌套对象创建新对象?

2 个答案:

答案 0 :(得分:0)

这是一个相当'脏'这样做的方法:

pre_save 处理程序中,您可以将 custom_target 重置为仅具有ID。像这样:

def pre_save(self, obj):
    if 'custom_target' in self.request.DATA:
        custom_target = self.request.DATA['custom_target']
        self.request.DATA['custom_target'] = custom_target['id']

现在无法想到任何更好/更清洁的解决方案,但如果找到一个,我会写出来:)

答案 1 :(得分:0)

在我看来,REST Framework中最常见的解决方案是分别使用嵌套的序列化程序和PrimaryKeyRelatedField。有了它,您可以将CustomTarget嵌套对象作为custom_target接收,并且可以在创建提供CustomTarget作为POST参数时将custom_target_id个对象与其关联。

class DataSetColumnSerializer(serializers.ModelSerializer):
    custom_target = target_serializers.CustomTargetSerializer(read_only=True)
    custom_target_id = serializers.PrimaryKeyRelatedField(source='custom_target')

class Meta:
    model = dataset_models.DataSetColumn

但是,您最终会得到两个属性custom_targetcustom_target_id,这些属性可能不会被视为理想选择。作为通用解决方案,可以实现自定义字段。

通用方法:自定义相关字段

class NestedRelatedField(serializers.PrimaryKeyRelatedField):
    def __init__(self, serializer_class, *args, **kwargs):
        self.serializer = serializer_class()
        super(NestedRelatedField, self).__init__(queryset=serializer_class.Meta.model.objects.all(), *args, **kwargs)

    def to_representation(self, instance):
        return self.serializer.to_representation(instance)

将其用作:

class DataSetColumnSerializer(serializers.ModelSerializer):
    custom_target = NestedRelatedField(CustomTargetSerializer)