我有两个模型可以通过 API 公开:每个RegionValue
has a ForeignKey
to a MapAnswer
。我希望在我们使用构建的 API 中表示这一点rest_framework
通过使RegionValue
s 内的一个字段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
那么它解决了这个问题,但我不想暴露主键!这RegionValue
s 是由它们唯一确定的region_id
和MapAnswer
他们与.
我解决这个问题的方法需要自定义 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(使用前将#替换为@)