[英]Django test client does not automatically serialize factories
Here's my code:这是我的代码:
# 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'),
This code works just fine if I visit /mypath
.如果我访问
/mypath
,这段代码就可以正常工作。 However, when I run an automated test using Django's test client, I get this error:但是,当我使用 Django 的测试客户端运行自动化测试时,出现以下错误:
*** TypeError: Object of type MyModel is not JSON serializable
this is my test: from django.test import TestCase, Client from blog.tests.factories.user import UserFactory from blog.tests.factories.post import PostFactory这是我的测试: 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
I suspect it has something to do with my factories:我怀疑这与我的工厂有关:
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')
How can I make my factories serializable?如何使我的工厂可序列化?
NOTE: This question is not a duplicate.注意:这个问题不是重复的。 The other questions linked have view handlers that return
HttpResponse
objects, instead of JsonResponse
objects.链接的其他问题具有返回
HttpResponse
对象而不是JsonResponse
对象的视图处理程序。 This distinction is key to my problem, because the error I'm seeing is related to JSON serialization that is supposed to be addressed by the JsonResponse
class.这种区别是我的问题的关键,因为我看到的错误与应该由
JsonResponse
类解决的 JSON 序列化有关。
Also, the other questions do not involve factories.另外,其他问题不涉及工厂。 Factories are another key component of what I'm trying to do, which is run integration tests against data generated by factories.
工厂是我正在尝试做的事情的另一个关键组成部分,即针对工厂生成的数据运行集成测试。
This code works just fine if I visit /mypath.
如果我访问/ mypath,这段代码就可以了。
I copy and paste your code and it raised a TypeError
as exactly same as this post, Django object is not JSON serializable 我复制并粘贴你的代码,它引发了一个与这篇文章完全相同的
TypeError
, Django对象不是JSON可序列化的
I don't think this is something wrong with your test client. 我不认为你的测试客户端有问题。 Change your
views.py
as below and try again. 将您的
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)})
This snippet will produce a JSON response as below, 此代码段将生成JSON响应,如下所示,
{
"models": [
{
"model": "account.mymodel",
"pk": 1,
"fields": {
"user": 74,
"name": "jerin"
}
},
{
"model": "account.mymodel",
"pk": 2,
"fields": {
"user": 66,
"name": "peter"
}
}
]
}
json.loads()
?? json.loads()
?? The serialized out put will be in string , we've to change it else, the Jsonresponse will be a string instead of Json 序列化的输出将是字符串 ,我们要改变它,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
Read more about Serialization of Django Objects/QuerySets 阅读有关Django对象/ QuerySet的序列化的更多信息
Why doesn't this work out of the box?
为什么这不是开箱即用的? It seems cumbersome to use.
使用起来似乎很麻烦。
I don't see any non-out of the box method here. 我在这里看不到任何非开箱即用的方法。 Because all things seem good, in Pythonic way and in Django way (my answer).
因为所有事情看起来都很好,以Pythonic方式和Django方式(我的回答)。
From here, we could understand what is a pure JSON. 从这里,我们可以理解什么是纯JSON。
An object is an unordered set of name/value pairs.
对象是一组无序的名称/值对。 An object begins with
{
(left brace) and ends with}
(right brace).对象以
{
(左括号)开头,以}
结尾(右大括号)。 Each name is followed by:
(colon) and the name/value pairs are separated by,
(comma).每个名称后面跟着
:
(结肠)和名称/值对被分离的,
(逗号)。
In your OP, you are trying to return {"models": list(MyModel.objects.all())}
which is a dict
but not a JSON
. 在你的OP中,你试图返回
{"models": list(MyModel.objects.all())}
这是一个dict
但不是JSON
。
Yeah...the outer layers are dict so it's can be a JSON Array . 是的...外层是dict所以它可以是一个JSON数组 。 But the Array contents are QuerySets , which is not a value according to this content
但是Array内容是QuerySets ,它不是根据此内容的值
I found a workaround to pass objects to the serializer class. 我找到了一个将对象传递给序列化程序类的解决方法。 Create a function as below,
创建如下函数,
from django.core import serializers
def serialize_dup(format, queryset, **options):
try: iter(queryset) except TypeError: queryset = [queryset]
return serializers.serialize(format, queryset, **options)
and use this serialize_dup()
funtion as usual serializers.serialize()
和通常的
serializers.serialize()
一样使用这个serialize_dup()
函数
As @fush suggested in comments, it's possible to return the JSON response if you serialize the model objects with format='python'
正如@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})
The code you shared assumes JSONResponse
will serialize an ORM object, but according to Django documentation, it won't:您共享的代码假定
JSONResponse
将序列化一个 ORM 对象,但根据 Django 文档,它不会:
https://docs.djangoproject.com/en/3.0/ref/request-response/#jsonresponse-objects https://docs.djangoproject.com/en/3.0/ref/request-response/#jsonresponse-objects
https://docs.djangoproject.com/en/3.0/topics/serialization/#djangojsonencoder https://docs.djangoproject.com/en/3.0/topics/serialization/#djangojsonencoder
It will work if you serialize the Django ORM object before passing it to JSONResponse
如果在将 Django ORM 对象传递给
JSONResponse
之前对其进行序列化,它将起作用
Consider doing the following:考虑执行以下操作:
from django.core import serializers
data = serializers.serialize("json", MyModel.objects.all())
https://docs.djangoproject.com/en/3.0/topics/serialization/ https://docs.djangoproject.com/en/3.0/topics/serialization/
django-rest-framework is a very popular lib used in scenarios like the one you shared https://docs.djangoproject.com/en/3.0/topics/serialization/#djangojsonencoder django-rest-framework 是一个非常流行的库,在您分享的场景中使用https://docs.djangoproject.com/en/3.0/topics/serialization/#djangojsonencoder
what about this:那这个呢:
def get_all_models(request):
return JsonResponse({"models": list(MyModel.objects.all().values())},safe=False)
the point is here:重点在这里:
MyModel.objects.all().values()
safe=False
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.