Django测试:如何通过client.post传递嵌套字典参数
Django测试客户端POST嵌套字典丢失数据的解决方法
问题场景
我有一个嵌套字典A,包含字典类型的值B:
B = {"k1": "v1", "k2": "v2", "k3": "v3",} A = {"User": B}
这个字典用于Django视图函数中:
def views_function(request): # 期望request.data是和A结构一致的嵌套字典
我基于django.test.TestCase编写单元测试时,发现测试客户端无法正确传递嵌套字典:
from django.test import TestCase class test_cases(TestCase): def setUp(self): self.B = {"k1": "v1", "k2": "v2", "k3": "v3",} self.A = {"User": self.B} self.url = reverse("views_function_url") def test_views_function(self): response = self.client.post(url, self.A, format="json")
测试函数里打印A是正常的,但视图中打印request.data.dict()时,只得到{'User': 'k3'},嵌套字典的其他键值对都丢失了。
问题原因
这是因为原生Django测试客户端的post方法默认使用表单编码(application/x-www-form-urlencoded)处理数据,这种编码格式不支持嵌套结构。它会把User对应的嵌套字典B拆解成User=k1&User=k2&User=k3的形式,而表单编码中同一个键重复出现时,只会保留最后一个值,所以最终User的值只剩下k3。
另外,原生Django测试客户端并不识别format="json"参数,所以即使加了这个参数,也不会自动把字典序列化为JSON格式。
解决方法
方法1:手动序列化JSON并指定Content-Type
使用json模块把嵌套字典序列化为JSON字符串,然后在post请求中明确指定content_type='application/json':
import json from django.test import TestCase class test_cases(TestCase): def setUp(self): self.B = {"k1": "v1", "k2": "v2", "k3": "v3",} self.A = {"User": self.B} self.url = reverse("views_function_url") def test_views_function(self): # 将嵌套字典转为JSON字符串 json_payload = json.dumps(self.A) # 发送POST请求,指定Content-Type为application/json response = self.client.post(self.url, json_payload, content_type='application/json')
方法2:使用DRF的APIClient(如果项目用了DRF)
如果你的项目基于Django REST Framework(DRF)开发,可以直接使用DRF提供的APIClient,它支持format="json"参数,能自动处理嵌套字典的序列化:
from rest_framework.test import APIClient from django.test import TestCase class test_cases(TestCase): def setUp(self): # 替换原生client为DRF的APIClient self.client = APIClient() self.B = {"k1": "v1", "k2": "v2", "k3": "v3",} self.A = {"User": self.B} self.url = reverse("views_function_url") def test_views_function(self): # format="json"会自动将嵌套字典序列化为JSON response = self.client.post(self.url, self.A, format="json")
验证修改
修改后,在视图函数中直接访问request.data(如果是DRF的Request对象),就能得到完整的嵌套字典:
def views_function(request): print(request.data) # 输出: {"User": {"k1": "v1", "k2": "v2", "k3": "v3"}}
内容的提问来源于stack exchange,提问作者Mistakamikaze
相关产品推荐
相关产品推荐

