创建使用Django的REST框架嵌套的序列化,但没有主键身份 [英] Create a nested serializer with Django Rest Framework, but without primary keys as identity
问题描述
我有两个型号通过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 RegionValue
s 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 $ C $确定C>与之关联。
This works fine from a read perspective, but updating the regionvalue_set
has an issue where new RegionValue
s 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 RegionValue
s 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屋!