创建使用Django的REST框架嵌套的序列化,但没有主键身份 [英] Create a nested serializer with Django Rest Framework, but without primary keys as identity

查看:316
本文介绍了创建使用Django的REST框架嵌套的序列化,但没有主键身份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个型号通过API暴露:每 RegionValue 有一个 ForeignKey的 MapAnswer 。我想重新这是我们的API中内置使用present rest_framework 通过里面的 RegionValue SA领域的 MapAnswer 端点。我的 rest_framework 串行器看起来是这样的:

I have two models to expose via an API: every RegionValue has a ForeignKey to a MapAnswer. I wish to represent this in our API built using rest_framework by making the RegionValues a field inside the MapAnswer endpoint. My rest_framework serializers looks like this:

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。如果我包括 RegionValueSerializer 领域的ID则解决了这个问题,但我preFER不暴露的主键!在 RegionValue s的唯一由他们的 REGION_ID MapAnswer 与之关联。

This works fine from a read perspective, but updating the regionvalue_set has an issue where new RegionValues are always created instead of linking to an existing RegionValue. If I include 'id' in the fields of RegionValueSerializer then it solves this problem, but I'd prefer not to expose the primary key! The RegionValues are uniquely determined by the their region_id and the MapAnswer they are associated with.

推荐答案

我解决了这个要求定制RegionValueSerializer,截取从原生的Python的数据类型转换到外地。方式

The way I solved this required customising the RegionValueSerializer, intercepting the conversion from native python data types to the field.

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 讨论的文档,所以我不知道如何稳定这将会。此外,该解决方案访问数据库不是真的有必要(对于现有值的查找,复制发生在父串行查询)。

Caveats: Note that some of these methods are not really discussed in rest_framework's docs, so I'm not sure how stable this will be. Also, this solution hits the database more than really necessary (the lookup for existing values is duplicating lookups that occur in the parent Serializer).

这篇关于创建使用Django的REST框架嵌套的序列化,但没有主键身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆