【问题标题】:Djongo Models - How to get rid of : Object of type AssertionError is not JSON serializableDjongo 模型 - 如何摆脱:AssertionError 类型的对象不是 JSON 可序列化的
【发布时间】:2021-01-06 10:52:31
【问题描述】:

我在我的 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__'

制作了这个外部脚本来测试发布请求是否顺利

注意身份验证令牌运行良好,一切顺利,只有创建不起作用 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

【问题讨论】:

    标签: python-3.x django django-rest-framework djongo


    【解决方案1】:

    问题

    这是您有问题的行:

    return(Response({'status':'failed' , 'error':ex}))
    

    您正在传递实际的执行对象 (ex) 作为响应的一部分,该响应又被序列化为 JSON。但是没有内置的方法可以做到这一点。

    解决办法

    您应该只返回消息,而不是返回整个异常。像这样的:

    return(Response({'status':'failed' , 'error':str(ex)}))
    

    还有……

    这样做是不好的做法:

    except Exception as ex:
    

    这将捕获您不想要的所有可能的错误。有些事情应该在不同的点上失败。 Django 内置了自己的异常处理功能,因此不会让您的服务器完全崩溃。如果出现了您不希望出现的问题,您需要知道这一点,并让错误一直冒泡。不是这样抓的。它使调试变得更加困难。

    捕获特定错误要好得多。这样做的另一个好处是您可以编写自己的消息,这对最终用户来说更有意义。例如:

    except AssertionError:
        return(Response(
             {'status':'failed' , 
              'error': 'Your own message here'
             })
        )
    

    【讨论】:

    • 非常感谢!哦,上帝……我真的根本没注意……但是,现在我得到了 ValueError: Value: None must be of type dict/list ,有什么想法吗?
    • hmm... 检查request.data 是否为无。这可能是你的问题?
    猜你喜欢
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 2021-12-10
    • 1970-01-01
    • 2021-09-27
    • 2019-09-04
    • 2019-01-12
    相关资源
    最近更新 更多