3

我有两个模型要通过 API 公开:每个模型RegionValue都有ForeignKey一个MapAnswer. 我希望rest_framework通过在端点RegionValue内创建 sa 字段来在我们构建的 API 中表示这一点。MapAnswer我的rest_framework序列化程序如下所示:

class RegionValueSerializer(serializers.ModelSerializer):

    class Meta:
        model = RegionValue
        fields = ('region_id', 'value')

class MapAnswerSerializer(serializers.ModelSerializer):
    regionvalue_set = RegionValueSerializer(many=True, allow_add_remove=True, required=False)
    declined = serializers.BooleanField(required=False)

    class Meta:
        model = MapAnswer
        fields = ('declined', 'regionvalue_set')

从读取的角度来看,这可以正常工作,但是更新regionvalue_set存在一个问题,RegionValue即总是创建新的而不是链接到现有的 RegionValue。如果我在字段中包含“id”,RegionValueSerializer那么它可以解决这个问题,但我不想公开主键!RegionValues 由它们region_idMapAnswer它们关联的唯一确定。

4

1 回答 1

3

我解决这个问题的方法需要自定义 RegionValueSerializer,拦截从原生 python 数据类型到字段的转换。

class RegionValueSerializer(serializers.ModelSerializer):

    def field_from_native(self, data, files, field_name, into):
        # We need to check all the data items, and ensure they
        # are matched to an existing primary id if they already
        # present

        # Returns nothing because this method mutates 'into'
        super(RegionValueSerializer, self).field_from_native(data, files, field_name, into)

        map_answer = self.parent.object
        new_into = []
        for rv in into.get('regionvalue_set'):
            if rv.id is None:
                try:
                    existing_rv = RegionValue.objects.get(answer=map_answer, region_id=rv.region_id)
                    existing_rv.value = rv.value
                    rv = existing_rv
                except RegionValue.DoesNotExist:
                    pass
            new_into.append(rv)
        into['regionvalue_set'] = new_into

    def get_identity(self, data):
        try:
            # Technically identity is defined by region_id AND self.parent.object.id,
            # but we assume that RegionValueSerializer will only ever be used as a
            # field that is part of MapAnswerSerializer.
            return data.get('region_id', None)
        except AttributeError:
            return None

注意事项:请注意,其中一些方法在rest_framework的文档中并未真正讨论过,因此我不确定这将有多稳定。此外,此解决方案对数据库的访问超出了实际需要(对现有值的查找是在父序列化程序中发生的重复查找)。

于 2013-11-12T21:55:07.587 回答