使用 Django Rest Framework 创建嵌套序列化器,但没有主键作为标识

2024-01-06

我有两个模型可以通过 API 公开:每个RegionValue has a ForeignKey to a MapAnswer。我希望在我们使用构建的 API 中表示这一点rest_framework通过使RegionValues 内的一个字段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他们与.


我解决这个问题的方法需要自定义 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

Caveats:请注意,其中一些方法并未在rest_framework的文档,所以我不确定这有多稳定。此外,此解决方案对数据库的影响超出了实际需要(对现有值的查找是重复父序列化程序中发生的查找)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Django Rest Framework 创建嵌套序列化器,但没有主键作为标识 的相关文章

随机推荐