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
相关产品推荐
相关产品推荐

