zoukankan      html  css  js  c++  java
  • json

    【已解决】Object of type 'QuerySet' is not JSON serializable

    原创 2017年09月01日 20:49:49

    报错图片

    报错的意思: QuerySet的数据格式不是JSON支持的序列化格式

    我的代码:

    [python] view plain copy
     
    1. def ajax_value(request):  
    2.   
    3.     ajax_testvalue = models.MonitorData02DB.objects.all().order_by("-id")[:1]  
    4.   
    5.     return JsonResponse(ajax_testvalue, safe=False)  

    这里要调用 from django.core import serializers 实现

    参考原帖地址: Django model,QuerySet 序列化成json的方法

    修改后

    [python] view plain copy
     
    1. def ajax_value(request):  
    2.   
    3.     ajax_testvalue = serializers.serialize("json", models.MonitorData02DB.objects.all().order_by("-id")[:1])  
    4.   
    5.     return HttpResponse(ajax_testvalue)  
    即可生成Json数据

    提到序列化与反序列化,通常会想到 json ,xml .在J2EE的开发中,这是很常用的技术,比如一个java class与xml之间的序列化与反序列化,我们可以通过 xstream来实现,如果是与json之间的转换,我们可以通过 gson.jar或者jsonlib.jar 来实现。方法很多,也是常见的方法。

    但在python 中,我们常用的是json 的序列化,python2.7 已经包含了json package,这个也是从simplejson 基础上改变而来。这个json 包主要提供了dump,load 来实现dict 与 字符串之间的序列化与反序列化,这很方便的可以完成,可以参考这篇文章python json。但现在的问题是,这个json包不能序列化 django 的models 里面的对象的实例。
    经过分析,网络搜索,发现有如下解决方案.

    利用 from django.core import serializers 的方法实现

    程序代码 程序代码

    from django.core import serializers
    data = serializers.serialize("json", SomeModel.objects.all())
    data1 = serializers.serialize("json", SomeModel.objects.filter(myfield1=myvalue))


    上面两个是没有问题的,因为序列化的对象是 Queryset, 因此是成功的。但如果是用SomeModel.objects.get(id=myid) 得到一个具体的实例的时候,问题就来了

    程序代码 程序代码

    data = serializers.serialize("json", SomeModel.objects.get(id=myid))


    肯定会出现如下错误:
    for obj in queryset:
    TypeError: 'SomeModel' object is not iterable
    一看错误就知道,因为  SomeModel.objects.get(id=myid) 返回的是一个具体的实例,而不是一个集合对象,因此是不可以 iterable 的。所以报错。

    从上面的分析可以看出  django的 serializers 只支持 queryset,而不支持model的实例,那么怎么实现呢?
    1.我们自己把这个单个对象模拟成一个集合,然后去掉前后的"[""]"符号,就可以了。

    程序代码 程序代码

    from django.utils import simplejson
    from django.db import models
    from django.core.serializers import serialize,deserialize
    from django.db.models.query import QuerySet
    from django.test import TestCase

    class MyEncoder(simplejson.JSONEncoder):
         """ 继承自simplejson的编码基类,用于处理复杂类型的编码
         """
         def default(self,obj):
                 if isinstance(obj,QuerySet):
                     """ Queryset实例
                     直接使用Django内置的序列化工具进行序列化
                     但是如果直接返回serialize('json',obj)
                     则在simplejson序列化时会被从当成字符串处理
                     则会多出前后的双引号
                     因此这里先获得序列化后的对象
                     然后再用simplejson反序列化一次
                     得到一个标准的字典(dict)对象
                     """
                     return simplejson.loads(serialize('json',obj))
                 if isinstance(obj,models.Model):
                     """
                     如果传入的是单个对象,区别于QuerySet的就是
                     Django不支持序列化单个对象
                     因此,首先用单个对象来构造一个只有一个对象的数组
                     这是就可以看做是QuerySet对象
                     然后此时再用Django来进行序列化
                     就如同处理QuerySet一样
                     但是由于序列化QuerySet会被'[]'所包围
                     因此使用string[1:-1]来去除
                     由于序列化QuerySet而带入的'[]'
                     """
                     return simplejson.loads(serialize('json',[obj])[1:-1])
                 if hasattr(obj, 'isoformat'):
                     #处理日期类型
                     return obj.isoformat()
                 return simplejson.JSONEncoder.default(self,obj)

    def jsonBack(json):
         """    进行Json字符串的反序列化
             一般来说,从网络得回的POST(或者GET)
             参数中所包含json数据
             例如,用POST传过来的参数中有一个key value键值对为
             request.POST['update']
             = "[{pk:1,name:'changename'},{pk:2,name:'changename2'}]"
             要将这个value进行反序列化
             则可以使用Django内置的序列化与反序列化
             但是问题在于
             传回的有可能是代表单个对象的json字符串
             如:
             request.POST['update'] = "{pk:1,name:'changename'}"
             这是,由于Django无法处理单个对象
             因此要做适当的处理
             将其模拟成一个数组,也就是用'[]'进行包围
             再进行反序列化
         """
         if json[0] == '[':
             return deserialize('json',json)
         else:
             return deserialize('json','[' + json +']')

    def getJson(**args):
         """    使用MyEncoder这个自定义的规则类来序列化对象
         """
         result = dict(args)
         return simplejson.dumps(result,cls=MyEncoder)


    在上面的例子中,自定义了一个序列化规则类MyEncoder,用来处理集合或者集合对象,然后实现了一个可变参数的工具方法getJson,用于传入多个参数,并将其一同序列化。另外还有一个反序列化对象的方法jsonBack,接受一个代表对象或者对象集合的json而返回一个对象集合。这样一来就可以很好的使用配合SimpleJson和Django来完成序列化工作了

    2.直接利用python 2.7 提供的json包,或者用simplejson都可以
    首先,你需要在django model的定义中增加一个方法toJSON,利用了django model  能访问 _meta.fields 得到相关属性而得到,例子如下

    程序代码 程序代码

    class Category(models.Model):
        autoid = models.AutoField(primary_key=True)
        email=models.CharField(max_length=150,blank=False)
        comtype=models.CharField(max_length=20,blank=False)
        catname=models.CharField(max_length=150,blank=False)  
        
        def __unicode__(self):
            return '%s' % (self.catname)
        
        def toJSON(self):
            import json
            return json.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))


    现在用django查出数据,并转换成json

    程序代码 程序代码

    row=models.Category.objects.get(autoid=23)    
    print row.toJSON()


    你会发现,成功转换了。当然,这个toJSON方法,如果要求可读性比较好的话,可以这样写

    程序代码 程序代码

    def toJSON(self):
        fields = []
        for field in self._meta.fields:
            fields.append(field.name)

        d = {}
        for attr in fields:
            d[attr] = getattr(self, attr)

        import json
        return json.dumps(d)
  • 相关阅读:
    第十三周学习进度
    第二次冲刺阶段每日任务02
    第二次冲刺阶段每日任务01
    构建之法阅读笔记03
    找水王续
    第十二周学习进度
    找水王
    第十一周学习进度
    博客园的用户体验
    找水王1
  • 原文地址:https://www.cnblogs.com/xc1234/p/8602440.html
Copyright © 2011-2022 走看看