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

使用APIClient和APITestCase无法复现POST请求:Payload字段丢失

问题:APIClient测试时标签未被正确关联,Swagger调用正常

场景复现

序列化器配置

class TagSerializer(serializers.Serializer):

    id = serializers.UUIDField(read_only=True)
    name = serializers.CharField(required=True)
    style = serializers.JSONField(read_only=True)


class TagCreationMixin:

    def create(self, validated_data):
        data = copy.deepcopy(validated_data)
        tags = data.pop("tags", [])
        item = self.Meta.model.objects.create(**data)
        for tag in tags:
            current_tag, _ = models.Tag.objects.get_or_create(**tag)
            item.tags.add(current_tag)
        return item

class ItemSerializer(TagCreationMixin, serializers.ModelSerializer):

    tags = TagSerializer(many=True, required=False)

    class Meta:
        model = models.Item
        fields = "__all__"

测试用例代码

class TestAPIMissingTags(APITestCase):

    fixtures = [
        "core/fixtures/users.yaml"
    ]

    payload = {
        "name": "test",
        "tags": [{"name": "test"}, {"name": "critical"}],
    }

    def setUp(self):
        self.user = models.CustomUser.objects.get(username="jlandercy")
        self.client = APIClient()
        self.client.force_authenticate(user=self.user)

    def test_complete_payload_is_sent(self):
        response = self.client.post("/api/core/item/", data=self.payload)
        print(response)
        print(response.json())

现象

  • APIClient测试返回201,但响应中tags为空数组:
    <Response status_code=201, "application/json">
    {'id': 'f3cd6bbb-239f-4f47-9b2d-f648ead76bdd', 'tags': [], 'name': 'test'}
    
  • 用Swagger调用相同接口和Payload,响应包含正确关联的标签:
    {
      "id": "6d05c2e3-fce3-420d-bef9-4bccd28062f7",
      "tags": [
        {
          "id": "fa70c875-818b-4ca2-9417-4209fd377453",
          "name": "test",
          "style": {
            "background-color": "#cc7a13"
          }
        },
        {
          "id": "9fd59657-4242-432f-b165-1ed0a67546e3",
          "name": "critical",
          "style": {
            "background-color": "#bf8100"
          }
        }
      ],
      "name": "test"
    }
    

原因分析

APIClient的post方法中,使用data参数时默认会把数据编码为表单格式(application/x-www-form-urlencoded),这种格式无法正确传递嵌套的复杂结构(比如包含字典的列表)。而Swagger发送的是JSON格式请求(Content-Type: application/json),DRF能正确解析嵌套数据。

当用data传递嵌套结构时,DRF的解析器无法识别tags字段的嵌套内容,导致validated_data中没有tags键,TagCreationMixin的create方法只能拿到空列表,最终没有关联任何标签。

解决方法

将post方法中的data参数替换为json参数,让APIClient发送JSON格式的请求:

def test_complete_payload_is_sent(self):
    response = self.client.post("/api/core/item/", json=self.payload)
    print(response)
    print(response.json())

这样请求会以application/json格式发送,DRF能正确解析tags字段的嵌套结构,validated_data中会包含完整的标签数据,create方法就能正常创建并关联标签,响应也会返回正确的标签列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 02:26:19