[英]Django test client does not automatically serialize factories
这是我的代码:
# models.py
class MyModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=10)
...
# views.py
def get_all_models(request):
return JsonResponse({"models": list(MyModel.objects.all())})
# urls.py
path('/mypath', views.get_all_models, name='get_all_models'),
如果我访问/mypath
,这段代码就可以正常工作。 但是,当我使用 Django 的测试客户端运行自动化测试时,出现以下错误:
*** TypeError: Object of type MyModel is not JSON serializable
这是我的测试: from django.test import TestCase, Client from blog.tests.factories.user import UserFactory from blog.tests.factories.post import PostFactory
class MyModelTest(TestCase):
def setUp(self):
self.user = UserFactory.create()
self.post = MyModelFactory.create(user=self.user)
self.client = Client()
def test_get_all_models(self):
response = self.client.get("/mypath")
pass
我怀疑这与我的工厂有关:
import factory
from .models import User, MyModel
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
username = factory.Faker('word')
email = factory.Faker('email')
class MyModelFactory(factory.django.DjangoModelFactory):
class Meta:
model = MyModel
user = factory.SubFactory(UserFactory)
name = factory.Faker('name')
如何使我的工厂可序列化?
注意:这个问题不是重复的。 链接的其他问题具有返回HttpResponse
对象而不是JsonResponse
对象的视图处理程序。 这种区别是我的问题的关键,因为我看到的错误与应该由JsonResponse
类解决的 JSON 序列化有关。
另外,其他问题不涉及工厂。 工厂是我正在尝试做的事情的另一个关键组成部分,即针对工厂生成的数据运行集成测试。
如果我访问/ mypath,这段代码就可以了。
我复制并粘贴你的代码,它引发了一个与这篇文章完全相同的TypeError
, Django对象不是JSON可序列化的
我不认为你的测试客户端有问题。 将您的views.py
更改为如下所示,然后重试。
from django.http.response import JsonResponse from django.core import serializers import json
def get_all_models(request):
data = serializers.serialize('json', MyModel.objects.all(), fields=('user', 'name'))
return JsonResponse({"models": json.loads(data)})
此代码段将生成JSON响应,如下所示,
{
"models": [
{
"model": "account.mymodel",
"pk": 1,
"fields": {
"user": 74,
"name": "jerin"
}
},
{
"model": "account.mymodel",
"pk": 2,
"fields": {
"user": 66,
"name": "peter"
}
}
]
}
json.loads()
?? 序列化的输出将是字符串 ,我们要改变它,Jsonresponse将是一个字符串而不是Json
In [1]: from account.models import MyModel
In [2]: from django.core import serializers
In [3]: data = serializers.serialize('json', MyModel.objects.all(), fields=('user', 'name'))
In [4]: data
Out[4]: '[{"model": "account.mymodel", "pk": 1, "fields": {"user": 74, "name": "jerin"}}, {"model": "account.mymodel", "pk": 2, "fields": {"user": 66, "name": "peter"}}]'
In [5]: type(data)
Out[5]: str
In [6]: import json
In [7]: data_new = json.loads(data)
In [8]: data_new
Out[8]:
[{'model': 'account.mymodel',
'pk': 1,
'fields': {'user': 74, 'name': 'jerin'}},
{'model': 'account.mymodel',
'pk': 2,
'fields': {'user': 66, 'name': 'peter'}}]
In [9]: type(data_new)
Out[9]: list
阅读有关Django对象/ QuerySet的序列化的更多信息
为什么这不是开箱即用的? 使用起来似乎很麻烦。
我在这里看不到任何非开箱即用的方法。 因为所有事情看起来都很好,以Pythonic方式和Django方式(我的回答)。
从这里,我们可以理解什么是纯JSON。
对象是一组无序的名称/值对。 对象以
{
(左括号)开头,以}
结尾(右大括号)。 每个名称后面跟着:
(结肠)和名称/值对被分离的,
(逗号)。
在你的OP中,你试图返回{"models": list(MyModel.objects.all())}
这是一个dict
但不是JSON
。
是的...外层是dict所以它可以是一个JSON数组 。 但是Array内容是QuerySets ,它不是根据此内容的值
我找到了一个将对象传递给序列化程序类的解决方法。 创建如下函数,
from django.core import serializers
def serialize_dup(format, queryset, **options):
try: iter(queryset) except TypeError: queryset = [queryset]
return serializers.serialize(format, queryset, **options)
和通常的serializers.serialize()
一样使用这个serialize_dup()
函数
正如@fush在注释中建议的那样,如果使用format='python'
序列化模型对象,则可以返回JSON响应
# code sample
from django.http.response import JsonResponse
from django.core import serializers
def get_all_models(request):
data = serializers.serialize('python', MyModel.objects.all(), fields=('user', 'name'))
return JsonResponse({"models": data})
您共享的代码假定JSONResponse
将序列化一个 ORM 对象,但根据 Django 文档,它不会:
https://docs.djangoproject.com/en/3.0/ref/request-response/#jsonresponse-objects
https://docs.djangoproject.com/en/3.0/topics/serialization/#djangojsonencoder
如果在将 Django ORM 对象传递给JSONResponse
之前对其进行序列化,它将起作用
考虑执行以下操作:
from django.core import serializers
data = serializers.serialize("json", MyModel.objects.all())
https://docs.djangoproject.com/en/3.0/topics/serialization/
django-rest-framework 是一个非常流行的库,在您分享的场景中使用https://docs.djangoproject.com/en/3.0/topics/serialization/#djangojsonencoder
那这个呢:
def get_all_models(request):
return JsonResponse({"models": list(MyModel.objects.all().values())},safe=False)
重点在这里:
MyModel.objects.all().values()
safe=False
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.