Djongo 模型 - 如何摆脱:AssertionError 类型的对象不是 JSON 可序列化的
Djongo Models - How to get rid of : Object of type AssertionError is not JSON serializable
我的 django Restfull 应用程序出现了一个奇怪的问题!
我正在使用 Djongo 作为数据库引擎 (MongoDB)
问题似乎发生在 /usr/local/lib/python3.8/dist-packages/rest_framework/utils/encoders.py 中,有时会说 create() 函数返回空对象或返回 AssertionError作为最后不可序列化的对象!
型号:
class Product(models.Model):
"""
Product Model
"""
_id = models.ObjectIdField()
name = models.CharField(max_length=MAX_PROD_NAME_LEN)
sku = models.CharField(max_length=MAX_PROD_SKU_LEN , unique=True)
category = models.CharField(max_length=MAX_PROD_CAT_LEN)
desc = models.TextField(default="")
agent_desc = models.TextField(default="")
urls = models.JSONField(blank=True , null=True)
productType = models.CharField(max_length=MAX_PROD_TYPE_LEN)
variants = models.JSONField(default={
# "op1":models.CharField(max_length=MAX_PROD_OPTION_LEN),
# "op2":models.CharField(max_length=MAX_PROD_OPTION_LEN),
# "op3":models.CharField(max_length=MAX_PROD_OPTION_LEN),
# "quantity":models.IntegerField(default=1),
# "price":models.DecimalField(max_digits=10, decimal_places=2),
})
options = models.JSONField(default={})
accessories = models.JSONField(default={
# "name" : None,
# "attachements":[],
# "quant" : None,
# "desc" : None
})
created_at = models.DateTimeField(auto_now_add=True , null=False)
updated_at = models.DateTimeField(auto_now=True, null=True)
deleted_at = models.DateTimeField(default=None)
is_deleted = models.BooleanField(default=False)
objects = models.DjongoManager() # built-in Model's objects Alike !
def __str__(self):
return self._id
查看:
class ProductView(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def list(self, request):
queryset = Product.objects.all()
serializer = ProductSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
print(f"Retrieving infos of {pk}")
queryset = Product.objects.all()
oid = None
try:
oid = ObjectId(pk)
except Exception:
return Response("Product not found !")
product = get_object_or_404(queryset, _id=oid)
serializer = ProductSerializer(product)
return Response(serializer.data)
def create(self, request):
try:
print(f'{type(request.data)} -- {dict(request.data)}')
serializer = ProductSerializer(data=dict(request.data))
prod = serializer.save()
# if serializer.is_valid(raise_exception=True):
return Response({'status':'success' , 'object':prod._id})
# else:
# return(Response({'status':'failed' , 'error':'Failed Creating Product'}))
except Exception as ex:
return(Response({'status':'failed' , 'error':ex}))
# def create(self, request, *args, **kwargs):
# response = super().create(request, *args, **kwargs)
# instance = response.data
# return Response({'status': 'success', 'pk': instance['pk']})
序列化器:
class ProductSerializer(ModelSerializer):
"""
Product Serialiazer !
"""
class Meta(object):
model = Product
fields = '__all__'
创建这个外部脚本来测试 post 请求是否正常
请注意,身份验证令牌运行良好,一切顺利,只有创建不起作用
Test_Post.py :
import requests as req
import json
from sys import argv
from datetime import datetime as dtm
link = 'http://localhost:8000/api/token/'
r=req.post(link , {'username':'root', 'password':'root'})
#print(r.text)
auth_access = json.loads(r.text)['access']
pyload = {
"name" : "prod2",
"sku" : f"asaasaku2{dtm.now()}",
"category" : "casaat2",
"desc" : "desasc2",
"agent_desc" : "asaagentDesc2",
"productType" : "typdef2f",
# "variants" : {
# "op1" : "o1",
# "op2" : "o2",
# "op3" : "o3",
# "quantity" : 10.0,
# "price" : 500.0
# },
# "accessories" : [
# "a1",
# "a2"
# ]
}
r = req.post(f'http://localhost:8000{argv[1]}', json=pyload, headers={'content-type':'application/json','Authorization':'Bearer '+str(auth_access)})
print(r.text)
错误:
Internal Server Error: /prods/
Traceback (most recent call last):
File "/usr/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/lib/python3.8/site-packages/django/core/handlers/base.py", line 145, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/lib/python3.8/site-packages/django/core/handlers/base.py", line 143, in _get_response
response = response.render()
File "/usr/lib/python3.8/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/usr/local/lib/python3.8/dist-packages/rest_framework/response.py", line 70, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "/usr/local/lib/python3.8/dist-packages/rest_framework/renderers.py", line 100, in render
ret = json.dumps(
File "/usr/local/lib/python3.8/dist-packages/rest_framework/utils/json.py", line 25, in dumps
return json.dumps(*args, **kwargs)
File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
return cls(
File "/usr/lib/python3.8/json/encoder.py", line 200, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.8/json/encoder.py", line 258, in iterencode
return _iterencode(o, 0)
File "/usr/local/lib/python3.8/dist-packages/rest_framework/utils/encoders.py", line 68, in default
return super().default(obj)
File "/usr/lib/python3.8/json/encoder.py", line 180, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type AssertionError is not JSON serializable
问题
这是你的问题行:
return(Response({'status':'failed' , 'error':ex}))
您正在传递实际的执行对象 (ex
) 作为响应的一部分,该对象又被序列化为 JSON。但是没有内置的方法可以做到这一点。
解决方案
而不是 return 处理整个异常,您应该 return 只处理消息。像这样:
return(Response({'status':'failed' , 'error':str(ex)}))
还有...
这样做是不好的做法:
except Exception as ex:
这将捕获您不想要的所有可能的错误。有些事情应该在不同的点失败。 Django 有它自己内置的异常处理,所以没有什么会完全崩溃你的服务器。如果出现了你不希望的错误,你需要知道这一点,并让错误一直冒出来。不是这样捕捉的。它使调试变得更加困难。
捕获特定错误要好得多。这样做的另一个好处是您可以编写自己的消息,这对最终用户来说更有意义。例如:
except AssertionError:
return(Response(
{'status':'failed' ,
'error': 'Your own message here'
})
)
我的 django Restfull 应用程序出现了一个奇怪的问题! 我正在使用 Djongo 作为数据库引擎 (MongoDB)
问题似乎发生在 /usr/local/lib/python3.8/dist-packages/rest_framework/utils/encoders.py 中,有时会说 create() 函数返回空对象或返回 AssertionError作为最后不可序列化的对象!
型号:
class Product(models.Model):
"""
Product Model
"""
_id = models.ObjectIdField()
name = models.CharField(max_length=MAX_PROD_NAME_LEN)
sku = models.CharField(max_length=MAX_PROD_SKU_LEN , unique=True)
category = models.CharField(max_length=MAX_PROD_CAT_LEN)
desc = models.TextField(default="")
agent_desc = models.TextField(default="")
urls = models.JSONField(blank=True , null=True)
productType = models.CharField(max_length=MAX_PROD_TYPE_LEN)
variants = models.JSONField(default={
# "op1":models.CharField(max_length=MAX_PROD_OPTION_LEN),
# "op2":models.CharField(max_length=MAX_PROD_OPTION_LEN),
# "op3":models.CharField(max_length=MAX_PROD_OPTION_LEN),
# "quantity":models.IntegerField(default=1),
# "price":models.DecimalField(max_digits=10, decimal_places=2),
})
options = models.JSONField(default={})
accessories = models.JSONField(default={
# "name" : None,
# "attachements":[],
# "quant" : None,
# "desc" : None
})
created_at = models.DateTimeField(auto_now_add=True , null=False)
updated_at = models.DateTimeField(auto_now=True, null=True)
deleted_at = models.DateTimeField(default=None)
is_deleted = models.BooleanField(default=False)
objects = models.DjongoManager() # built-in Model's objects Alike !
def __str__(self):
return self._id
查看:
class ProductView(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def list(self, request):
queryset = Product.objects.all()
serializer = ProductSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
print(f"Retrieving infos of {pk}")
queryset = Product.objects.all()
oid = None
try:
oid = ObjectId(pk)
except Exception:
return Response("Product not found !")
product = get_object_or_404(queryset, _id=oid)
serializer = ProductSerializer(product)
return Response(serializer.data)
def create(self, request):
try:
print(f'{type(request.data)} -- {dict(request.data)}')
serializer = ProductSerializer(data=dict(request.data))
prod = serializer.save()
# if serializer.is_valid(raise_exception=True):
return Response({'status':'success' , 'object':prod._id})
# else:
# return(Response({'status':'failed' , 'error':'Failed Creating Product'}))
except Exception as ex:
return(Response({'status':'failed' , 'error':ex}))
# def create(self, request, *args, **kwargs):
# response = super().create(request, *args, **kwargs)
# instance = response.data
# return Response({'status': 'success', 'pk': instance['pk']})
序列化器:
class ProductSerializer(ModelSerializer):
"""
Product Serialiazer !
"""
class Meta(object):
model = Product
fields = '__all__'
创建这个外部脚本来测试 post 请求是否正常
请注意,身份验证令牌运行良好,一切顺利,只有创建不起作用 Test_Post.py :
import requests as req
import json
from sys import argv
from datetime import datetime as dtm
link = 'http://localhost:8000/api/token/'
r=req.post(link , {'username':'root', 'password':'root'})
#print(r.text)
auth_access = json.loads(r.text)['access']
pyload = {
"name" : "prod2",
"sku" : f"asaasaku2{dtm.now()}",
"category" : "casaat2",
"desc" : "desasc2",
"agent_desc" : "asaagentDesc2",
"productType" : "typdef2f",
# "variants" : {
# "op1" : "o1",
# "op2" : "o2",
# "op3" : "o3",
# "quantity" : 10.0,
# "price" : 500.0
# },
# "accessories" : [
# "a1",
# "a2"
# ]
}
r = req.post(f'http://localhost:8000{argv[1]}', json=pyload, headers={'content-type':'application/json','Authorization':'Bearer '+str(auth_access)})
print(r.text)
错误:
Internal Server Error: /prods/
Traceback (most recent call last):
File "/usr/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/lib/python3.8/site-packages/django/core/handlers/base.py", line 145, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/lib/python3.8/site-packages/django/core/handlers/base.py", line 143, in _get_response
response = response.render()
File "/usr/lib/python3.8/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/usr/local/lib/python3.8/dist-packages/rest_framework/response.py", line 70, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "/usr/local/lib/python3.8/dist-packages/rest_framework/renderers.py", line 100, in render
ret = json.dumps(
File "/usr/local/lib/python3.8/dist-packages/rest_framework/utils/json.py", line 25, in dumps
return json.dumps(*args, **kwargs)
File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
return cls(
File "/usr/lib/python3.8/json/encoder.py", line 200, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.8/json/encoder.py", line 258, in iterencode
return _iterencode(o, 0)
File "/usr/local/lib/python3.8/dist-packages/rest_framework/utils/encoders.py", line 68, in default
return super().default(obj)
File "/usr/lib/python3.8/json/encoder.py", line 180, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type AssertionError is not JSON serializable
问题
这是你的问题行:
return(Response({'status':'failed' , 'error':ex}))
您正在传递实际的执行对象 (ex
) 作为响应的一部分,该对象又被序列化为 JSON。但是没有内置的方法可以做到这一点。
解决方案
而不是 return 处理整个异常,您应该 return 只处理消息。像这样:
return(Response({'status':'failed' , 'error':str(ex)}))
还有...
这样做是不好的做法:
except Exception as ex:
这将捕获您不想要的所有可能的错误。有些事情应该在不同的点失败。 Django 有它自己内置的异常处理,所以没有什么会完全崩溃你的服务器。如果出现了你不希望的错误,你需要知道这一点,并让错误一直冒出来。不是这样捕捉的。它使调试变得更加困难。
捕获特定错误要好得多。这样做的另一个好处是您可以编写自己的消息,这对最终用户来说更有意义。例如:
except AssertionError:
return(Response(
{'status':'failed' ,
'error': 'Your own message here'
})
)