You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest嵌套Serializer测试方法及多对多关联请求排障

解决Django REST Framework嵌套Serializer测试时字段丢失问题

问题根源

你测试时使用self.client.put(path, data)的写法,默认会把data以**表单编码(application/x-www-form-urlencoded)**发送,这种格式无法正确解析嵌套的字典数组结构(比如tasklists里的{"pk": "..."}),导致DRF的解析器无法识别tasklists字段,自然不会出现在validated_data或initial_data中。

正确的测试请求写法

必须显式指定请求的content_type为application/json,并将数据序列化为JSON字符串传递:

import json
from django.test import TestCase

class TaskUpdateTestCase(TestCase):
    def test_update_task_associated_lists(self):
        path = self.task.get_absolute_api_url()
        data = {
            "title": "hello",
            "tasklists": [
                {"pk": "b84d3375-0e09-4dd1-9809-f92d29d6aa36"},
                {"pk": "b84d3375-0e09-4dd1-9809-f92d29d6aa36"}
            ]
        }
        # 转换为JSON字符串并指定content_type
        response = self.client.put(
            path,
            data=json.dumps(data),
            content_type="application/json"
        )
        
        # 验证响应与数据库变更
        self.assertEqual(response.status_code, 200)
        updated_task = Task.objects.get(pk=self.task.pk)
        # 由于两个pk相同,实际关联的TaskList数量为1
        self.assertEqual(updated_task.tasklists.count(), 1)

通用测试嵌套Serializer的方法

可以从序列化输出、反序列化验证、视图请求三个层面进行测试:

1. 测试序列化输出

验证Serializer将模型实例转换为JSON结构是否符合预期:

def test_task_serializer_output(self):
    # 准备测试数据
    test_list = TaskList.objects.create(
        pk="b84d3375-0e09-4dd1-9809-f92d29d6aa36",
        name="工作清单"
    )
    test_task = Task.objects.create(title="完成文档")
    test_task.tasklists.add(test_list)
    
    # 序列化实例
    serializer = TaskSerializer(test_task)
    
    # 断言输出结构
    expected_data = {
        "title": "完成文档",
        "tasklists": [{"pk": "b84d3375-0e09-4dd1-9809-f92d29d6aa36"}]
        # 补充Serializer中定义的其他字段
    }
    self.assertEqual(serializer.data, expected_data)

2. 测试反序列化验证

验证传入的JSON数据能被正确解析、验证并保存:

def test_task_serializer_deserialization(self):
    # 提前创建关联的TaskList
    test_list = TaskList.objects.create(
        pk="b84d3375-0e09-4dd1-9809-f92d29d6aa36",
        name="工作清单"
    )
    
    # 构造符合格式的输入数据
    input_data = {
        "title": "新任务",
        "tasklists": [{"pk": "b84d3375-0e09-4dd1-9809-f92d29d6aa36"}]
    }
    
    # 验证数据有效性并保存
    serializer = TaskSerializer(data=input_data)
    self.assertTrue(serializer.is_valid())
    saved_task = serializer.save()
    
    # 断言保存结果
    self.assertEqual(saved_task.title, "新任务")
    self.assertIn(test_list, saved_task.tasklists.all())

3. 视图层集成测试

结合测试客户端发送真实请求,验证视图处理嵌套数据的逻辑是否正常:

def test_task_update_view(self):
    test_list = TaskList.objects.create(
        pk="b84d3375-0e09-4dd1-9809-f92d29d6aa36",
        name="工作清单"
    )
    test_task = Task.objects.create(title="旧标题")
    path = test_task.get_absolute_api_url()
    
    # 构造更新数据并发送JSON请求
    update_data = {
        "title": "更新后的标题",
        "tasklists": [{"pk": test_list.pk}]
    }
    response = self.client.put(
        path,
        json.dumps(update_data),
        content_type="application/json"
    )
    
    # 断言响应与数据库状态
    self.assertEqual(response.status_code, 200)
    updated_task = Task.objects.get(pk=test_task.pk)
    self.assertEqual(updated_task.title, "更新后的标题")
    self.assertEqual(updated_task.tasklists.first(), test_list)

内容的提问来源于stack exchange,提问作者Rauf Masoumi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:20:40