DRF提交带ManyToMany多对多字段的模型数据报类型错误如何解决
报错"Incorrect type. Expected pk value, received str"解决
- 首先检查请求头是否正确配置
Content-Type: application/json,如果使用form-data/x-www-form-urlencoded格式提交数组参数,DRF会默认将数组解析为字符串,触发类型错误。 - 其次检查提交的
tags_ids数组元素是否为数字类型,若提交的是字符串格式的ID如["2","4"]也会触发该错误,可在序列化器字段中添加类型转换逻辑兼容:
tags_ids = serializers.ListField( child=serializers.PrimaryKeyRelatedField(queryset=Tag.objects.all()), write_only=True )
- 你当前的序列化器仅定义了
tags_ids字段,没有将其值关联到实际的tags多对多字段,所以即使提交成功,关联关系也不会保存,需要补充create和update方法处理关联逻辑:
class DealSerializer(serializers.ModelSerializer): user = UserSerializer(many=False, read_only=True) tags = TagSerializer(many=True, read_only=True) tags_ids = serializers.PrimaryKeyRelatedField(many=True, write_only=True, queryset=Tag.objects.all()) class Meta: model = Deal fields = '__all__' def create(self, validated_data): tags_ids = validated_data.pop('tags_ids', []) deal = super().create(validated_data) deal.tags.set(tags_ids) return deal def update(self, instance, validated_data): tags_ids = validated_data.pop('tags_ids', []) deal = super().update(instance, validated_data) deal.tags.set(tags_ids) return deal
更优方案:单个字段实现读写兼容(读返回标签对象、写接收ID)
无需拆分tags和tags_ids两个字段,可通过重写to_representation方法直接复用同一个tags字段,代码更简洁,也符合DRF最佳实践,同时天然满足「标签必须预先创建不能通过Deal接口新建」的约束:
class DealSerializer(serializers.ModelSerializer): user = UserSerializer(many=False, read_only=True) tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all()) class Meta: model = Deal fields = '__all__' def to_representation(self, instance): rep = super().to_representation(instance) # 序列化输出时将ID替换为完整的Tag对象 rep['tags'] = TagSerializer(instance.tags.all(), many=True).data return rep
该方案下直接提交tags: [2,4]即可完成写操作,读接口会自动返回完整的标签对象。
内容的提问来源于stack exchange,提问作者coredumped0x
相关产品推荐
相关产品推荐

