Django Rest Framework多对多字段序列化问题求解
问题解决:Django REST Framework多对多字段序列化报错处理
问题背景
现有Django模型MaterialAttribute和MaterialType(多对多关联),需要实现MaterialTypeSerializer满足:
- 列表/详情接口返回
attributes的完整JSON结构(包含id和name) - 创建/更新时接收
attributes的主键列表
当前实现自定义MaterialAttributeManyField继承PrimaryKeyRelatedField并重写to_representation返回序列化后的字典,运行时出现unhashable type: 'ReturnDict'错误,要求不重写create和update方法解决。
错误原因
PrimaryKeyRelatedField内部处理多对多关系时,依赖返回的可哈希值(默认是主键)来做数据匹配与存储。自定义字段中to_representation返回了MaterialAttributeSerializer生成的ReturnDict(不可哈希类型),导致DRF内部处理逻辑出错。
简洁解决方案
不需要自定义字段,直接在MaterialTypeSerializer中重写to_representation方法,实现输入用主键、输出用完整结构的分离,同时保留DRF原生的多对多字段处理逻辑:
class MaterialAttributeSerializer(serializers.ModelSerializer): """ Serializer for MaterialAttribute model """ class Meta: model = MaterialAttribute fields = ["id", "name"] class MaterialTypeSerializer(serializers.ModelSerializer): """ Serializer for MaterialType model - 输入:接收attributes主键列表 - 输出:返回attributes完整JSON结构 """ attributes = serializers.PrimaryKeyRelatedField( queryset=MaterialAttribute.objects.all(), many=True ) class Meta: model = MaterialType fields = ["id", "name", "attributes"] def to_representation(self, instance): # 先调用父类获取基础序列化数据 data = super().to_representation(instance) # 将attributes字段替换为完整的序列化结构 data["attributes"] = MaterialAttributeSerializer( instance.attributes.all(), many=True ).data return data
效果说明
- 创建/更新:直接传入
attributes主键列表(如{"name": "Test", "attributes": [1,2]}),DRF通过PrimaryKeyRelatedField自动验证并处理多对多关系的保存,无需重写create/update。 - 列表/详情返回:
to_representation方法会自动将attributes替换为包含id和name的完整JSON结构,符合需求示例。
补充说明
若需要兼容用户提供的创建示例格式(数组内为包含主键的对象,如[{"id":1}, {"id":2}]),只需将PrimaryKeyRelatedField调整为:
attributes = serializers.PrimaryKeyRelatedField( queryset=MaterialAttribute.objects.all(), many=True, source="id" )
但更规范的做法是直接传递主键数组,上述基础方案已覆盖标准场景。
内容的提问来源于stack exchange,提问作者PKonline
相关产品推荐
相关产品推荐

