簡體   English   中英

Django 測試客戶端不會自動序列化工廠

[英]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,這段代碼就可以了。

我復制並粘貼你的代碼,它引發了一個與這篇文章完全相同的TypeErrorDjango對象不是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的序列化的更多信息



UPDATE-1

為什么這不是開箱即用的? 使用起來似乎很麻煩。

我在這里看不到任何非開箱即用的方法。 因為所有事情看起來都很好,以Pythonic方式和Django方式(我的回答)。

這里,我們可以理解什么是純JSON。

對象是一組無序的名稱/值對。 對象以{ (左括號)開頭,以}結尾(右大括號)。 每個名稱后面跟着: (結腸)和名稱/值對被分離的, (逗號)。

在你的OP中,你試圖返回{"models": list(MyModel.objects.all())}這是一個dict但不是JSON
是的...外層是dict所以它可以是一個JSON數組 但是Array內容是QuerySets ,它不是根據此內容


UPDATE-2

我找到了一個將對象傳遞給序列化程序類的解決方法。 創建如下函數,

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()函數


更新3

正如@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM