Django ModelViewSet单元测试报ValueError:解包值不足求助
你遇到的这个ValueError: not enough values to unpack (expected 2, got 1)错误,根源在于GET请求的参数传递方式错误,同时你的ViewSet逻辑也存在对GET请求参数获取的误区,下面一步步给你拆解修复:
1. 错误原因解析
测试代码的问题
DRF的APIClient.get()方法中,data参数的作用是构造URL的查询字符串(也就是?key=value这种形式),它需要接收一个字典,而你传入的是json.dumps(self.block_get_data)生成的JSON字符串。当DRF尝试把这个字符串转换成查询参数时,会把它当成一个键值对来解析,自然就会抛出“缺少值”的错误——因为字符串本身不是键值对结构。
另外,GET请求通常不会携带JSON格式的请求体,你设置content_type='application/json'对于GET请求来说是无效的,服务器端也不会从请求体里读取GET参数。
ViewSet的问题
你的TemplateView.list()方法里用了request.data['param']来获取参数,但request.data是用来获取POST/PUT等请求的请求体数据的,GET请求的参数应该从request.query_params(或者request.GET)里获取。
2. 修复步骤
第一步:修正测试代码
把测试中client.get()的data参数改成直接传字典,去掉json.dumps和content_type参数,同时修正你写错的参数传递:
def test_get_blocks(self): """Test get list of Block. """ response = self.client.get( "/api/v1/financing-settings/template/", data=self.block_get_data # 直接传字典,不要转JSON ) self.assertEqual(response.status_code, 200) def test_get_steps(self): """Test get list of Step. """ response = self.client.get( "/api/v1/financing-settings/template/", data=self.step_get_data # 修正之前传错的参数 ) self.assertEqual(response.status_code, 200) def test_no_step_or_block(self): """Test get no list of Step or Block. """ response = self.client.get( "/api/v1/financing-settings/template/", data=self.get_no_data ) self.assertEqual(response.status_code, 204)
第二步:修正ViewSet的参数获取逻辑
把request.data['param']改成从request.query_params获取,同时修复Step查询的序列化问题:
class TemplateView(ModelViewSet): """ViewSet for Saving Block/ Step template.""" def list(self, request, *args, **kwargs): """Get list of Block/Steps with is_process_template is equal to True.""" param = request.query_params.get('param') # 从查询参数获取 if param == "block": _block = Block.objects.filter(is_process_template=True).values() return JsonResponse({"data": list(_block)}, safe=False, status=200) elif param == "step": _step = Step.objects.filter(is_process_template=True).values() # 新增.values(),否则QuerySet无法直接转JSON return JsonResponse({"data": list(_step)}, safe=False, status=200) return Response(status=status.HTTP_204_NO_CONTENT)
3. 额外优化建议
- 对于ModelViewSet,其实可以不用自己重写
list方法,通过设置queryset和serializer_class,再结合django-filter过滤类来实现参数过滤,这样更符合DRF的规范。 - 测试中可以用
reverse函数反向解析URL代替硬编码的URL,后续URL变更时不需要修改测试代码。
内容的提问来源于stack exchange,提问作者Lutaaya Huzaifah Idris

