3

API 経由で公開する 2 つのモデルがRegionValueありForeignKeyますMapAnswer。エンドポイント内に sa フィールドrest_frameworkを作成することによって構築された API でこれを表現したいと考えています。私のシリアライザーは次のようになります。RegionValueMapAnswerrest_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 にリンクするのではなく、常にregionvalue_set新しい が作成されるという問題があります。RegionValueフィールドに「id」を含めると、RegionValueSerializerこの問題は解決しますが、主キーを公開したくないです! は、theirおよびthey が関連付けられているRegionValueによって一意に決定されます。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 に答える