Django Serializer设置已存在ManyToMany属性时抛Invalid pk不存在错误
错误原因
- 核心问题出在
multipart/form-data类型请求的参数处理逻辑:当请求携带文件时,Django REST Framework会将request.data解析为QueryDict实例,而非JSON请求对应的原生Python字典。QueryDict默认仅支持存储字符串/文件类型的单值,直接对key赋值列表时,会自动将整个列表做字符串序列化,你赋值的['video']最终会被存储为字符串"['video']"。 - 序列化器校验
hash_tags字段时,会将收到的字符串"['video']"当做主键去查询HashTag表,自然找不到对应记录,因此抛出Invalid pk "[\'video\']" - object does not exist.的错误。 - 不带文件的JSON请求可以正常运行,是因为JSON请求的
request.data是原生字典,支持列表类型的原生存储,序列化器可以正常解析列表中的每个主键值。
规范解决方案
方案1(最优):绕过request.data传参,直接在save阶段注入关联标签
你提取hash_tags的逻辑完全在后端实现,不需要通过请求参数传递,因此不需要把hash_tags塞入request.data,可以直接在序列化器保存时传入,彻底规避QueryDict的格式问题:
- 首先修改
set_request_data_for_post函数,不再操作request.data的hash_tags字段,改为返回提取到的标签对象列表:
from django.http.request import QueryDict def set_request_data_for_post(request, user_uuid: str): if isinstance(request.data, QueryDict): request.data._mutable = True request.data['creator'] = user_uuid post_text = request.data['body'] hash_tags_list = extract_hashtags(post_text) # 直接返回HashTag对象列表,不需要转成主键字符串 hash_tags = [HashTag.objects.get_or_create(hash_tag=ht)[0] for ht in hash_tags_list] if isinstance(request.data, QueryDict): request.data._mutable = False return request, hash_tags
- 调整
create_post逻辑,保存序列化器时传入标签列表:
def create_post(request): user_uuid = str(request.user.uuid) request, hash_tags = set_request_data_for_post(request=request, user_uuid=user_uuid) try: serializer = CreatePostSerializer(data=request.data) if serializer.is_valid(raise_exception=True): # 保存时传入hash_tags,DRF会自动处理多对多关联 post_obj = serializer.save(hash_tags=hash_tags) except Exception as e: return Response(dict(error=str(e), user_message=error_message_generic), status=status.HTTP_400_BAD_REQUEST) return Response(serializer.data, status=status.HTTP_201_CREATED)
- 可选:如果不需要前端传入hash_tags,可以直接把
hash_tags从CreatePostSerializer的fields列表中移除,避免不必要的校验。
方案2:适配QueryDict的列表赋值规则
如果你一定要通过request.data传递hash_tags,需要用QueryDict专属的setlist方法赋值列表,同时提前修改QueryDict的可编辑属性:
from django.http.request import QueryDict def set_request_data_for_post(request, user_uuid: str): # 先开启QueryDict的可编辑权限 if isinstance(request.data, QueryDict): request.data._mutable = True request.data['creator'] = user_uuid post_text = request.data['body'] hash_tags_list = extract_hashtags(post_text) hash_tags = [HashTag.objects.get_or_create(hash_tag=ht)[0].hash_tag for ht in hash_tags_list] if len(hash_tags) > 0: # 用setlist方法赋值列表,不要直接用=赋值 request.data.setlist('hash_tags', hash_tags) # 关闭可编辑权限,避免后续异常 if isinstance(request.data, QueryDict): request.data._mutable = False return request
内容的提问来源于stack exchange,提问作者user12314098
相关产品推荐
相关产品推荐

