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

Django反序列化报错TypeError: string indices must be integers, not 'str'

问题:Django测试中反序列化JSONResponse触发DeserializationError

错误场景

为图书博客文章实现AJAX标签筛选功能,采用TDD验证标签筛选逻辑时,测试用例中反序列化JsonResponse内容并迭代时触发错误。

错误日志

File "E:\04_projects\01_Python\10_book_blog\venv\Lib\site-packages\django\core\serializers\json.py", line 70, in Deserializer
    yield from PythonDeserializer(objects, **options)
File "E:\04_projects\01_Python\10_book_blog\venv\Lib\site-packages\django\core\serializers\python.py", line 111, in Deserializer
    Model = _get_model(d["model"])
                       ~^^^^^^^^^
TypeError: string indices must be integers, not 'str'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "E:\04_projects\01_Python\10_book_blog\posts\tests\test_views.py", line 103, in test_returns_filtered_posts
    for obj in decereal:
  File "E:\04_projects\01_Python\10_book_blog\venv\Lib\site-packages\django\core\serializers\json.py", line 74, in Deserializer
    raise DeserializationError() from exc
django.core.serializers.base.DeserializationError

相关代码

测试用例代码

def test_returns_filtered_posts(self):
        # 创建一篇带标签的文章和一篇不带标签的文章
        t1 = Tag.objects.create(tag_name='test', group_name='general')
        p1 = Post.objects.create(book_title='test_book')
        p2 = Post.objects.create(book_title='test_book2')
        p1.tags.add(t1)

        # 模拟点击'test'标签的请求
        response = self.client.post(reverse('ajax_post'), {'tag[]': ['test', 'general']})
        # 反序列化数据
        decereal = deserialize('json', response.content)
        # 调试打印
        for obj in decereal:
            print(obj)
        # 测试逻辑(未执行到此处)
        self.assertNotIn(p2, decereal)

视图代码

def ajax_call(request):
    data = serializers.serialize('json', Post.objects.all())
    # 仅用于测试的反序列化操作
    uncereal = serializers.deserialize('json', data)
    return JsonResponse(data, safe=False)

问题根源

视图中serializers.serialize('json', ...)生成的是JSON格式的字符串,直接传给JsonResponse时,会对这个字符串再次进行JSON序列化,导致返回的响应内容是一个被转义的JSON字符串(而非原始的对象数组)。

举个例子:

  • 原始序列化结果:[{"model": "posts.post", ...}]
  • 经过JsonResponse处理后变成:"[{\"model\": \"posts.post\", ...}]"

当测试用例调用deserialize('json', response.content)时,实际解析的是一个字符串,而非对象数组,因此迭代时会触发“string indices must be integers”错误。

解决方案

1. 修复视图代码

避免对序列化后的JSON字符串重复序列化,改为返回Python对象列表:

from django.core import serializers
from django.http import JsonResponse

def ajax_call(request):
    # 使用'python'格式直接获取序列化后的Python对象列表
    data = serializers.serialize('python', Post.objects.all())
    return JsonResponse(data, safe=False)

或者先解析JSON字符串再返回:

import json
from django.core import serializers
from django.http import JsonResponse

def ajax_call(request):
    serialized_str = serializers.serialize('json', Post.objects.all())
    data = json.loads(serialized_str)
    return JsonResponse(data, safe=False)

2. 修复测试用例的断言逻辑

deserialize返回的是DeserializedObject实例,而非原始的Post对象,需要提取object属性来断言:

def test_returns_filtered_posts(self):
        # 创建一篇带标签的文章和一篇不带标签的文章
        t1 = Tag.objects.create(tag_name='test', group_name='general')
        p1 = Post.objects.create(book_title='test_book')
        p2 = Post.objects.create(book_title='test_book2')
        p1.tags.add(t1)

        # 模拟点击'test'标签的请求
        response = self.client.post(reverse('ajax_post'), {'tag[]': ['test', 'general']})
        # 反序列化数据
        deserialized = deserialize('json', response.content)
        # 提取实际的Post对象
        returned_posts = [obj.object for obj in deserialized]
        # 执行测试断言
        self.assertIn(p1, returned_posts)
        self.assertNotIn(p2, returned_posts)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 14:17:06