Django 允许您使用item 属性访问您的Pin 上的项目,但实际上将关系存储为item_id。您可以在序列化程序中使用此策略来解决 Python 对象不能具有两个同名属性的事实(您会在代码中遇到的问题)。
最好的方法是使用PrimaryKeyRelatedField 和source 参数。这将确保完成正确的验证,在字段验证期间将"item_id": <id> 转换为"item": <instance>(紧接在序列化程序的validate 调用之前)。这允许您在validate、create 和update 方法期间操作整个对象。您的最终代码将是:
class PinSerializer(serializers.ModelSerializer):
item = ItemSerializer(read_only=True)
item_id = serializers.PrimaryKeyRelatedField(write_only=True,
source='item',
queryset=Item.objects.all())
class Meta:
model = Pin
fields = ('id', 'item', 'item_id',)
注意 1:我还删除了读取字段上的 source='item',因为那是多余的。
注意 2:实际上,我发现 Django Rest 的设置相当不直观,因此没有指定 Item 序列化器的 Pin 序列化器将 item_id 返回为"item": <id> 而不是"item_id": <id>,但这不是重点。
此方法甚至可以用于正向和反向“多”关系。例如,您可以使用 pin_ids 的数组来设置 Item 上的所有 Pins,代码如下:
class ItemSerializer(serializers.ModelSerializer):
pins = PinSerializer(many=True, read_only=True)
pin_ids = serializers.PrimaryKeyRelatedField(many=True,
write_only=True,
source='pins',
queryset=Pin.objects.all())
class Meta:
model = Item
fields = ('id', 'pins', 'pin_ids',)
我之前推荐的另一个策略是使用IntegerField 直接设置item_id。假设您使用 OneToOneField 或 ForeignKey 将您的 Pin 与您的项目相关联,您可以将 item_id 设置为整数而不使用 item 字段。这会削弱验证,并可能导致违反约束的 DB 级错误。如果您想跳过验证数据库调用,在验证/创建/更新代码中需要 ID 而不是对象,或者需要同时具有相同源的可写字段,这可能会更好,但我不会再推荐。整行是:
item_id = serializers.IntegerField(write_only=True)