【问题标题】:JSON serialize/encoding in mongoenginemongoengine中的JSON序列化/编码
【发布时间】:2014-10-15 22:49:09
【问题描述】:

我可能在做一些愚蠢的事情,但我在 mongo 中有一个类似于以下内容的序列化程序:

from json import JSONEncoder
from pymongo.objectid import ObjectId

class MongoEncoder(JSONEncoder):
    def default(self, obj, **kwargs):
        if isinstance(obj, ObjectId):
            return str(obj)
        else:            
            return JSONEncoder.default(obj, **kwargs)

现在如果我这样做:

obj = Model.objects().first()
json.dumps(obj, cls=MongoEncoder)

我收到一个错误:

TypeError: unbound method default() must be called with JSONEncoder instance as first argument (got Allocation instance instead)

稍微挖掘了一下,发现在回调 MongoEncoder 类的过程中,第一个传递给默认值的“obj”是 obj 本身,而不是 obj 的组件。在过去的某个时候,我有这个工作,但我认为它会智能地迭代传递给 json.dumps 命令的 obj 的组件(即,传递给 MongoEncoder.default 的所有内容都是原始 obj 的字段,不是 obj 本身。

我错过了什么吗?

【问题讨论】:

    标签: python json mongodb serialization mongoengine


    【解决方案1】:

    错误在你的最后一行:

    return JSONEncoder.default(obj, **kwargs)
    

    应该是:

    return JSONEncoder.default(self, obj)
    

    标准的default 方法不接受kwargs(here 是文档),所以你不应该通过它们。

    【讨论】:

      【解决方案2】:

      按照docs 上的文档,我使用以下代码完成了它:

      class MongoEncoder(JSONEncoder):
          def default(self, obj):
              if isinstance(obj, Place):
                  return obj.to_dict()
              return JSONEncoder.default(self, obj)
      

      这样我可以称它为传递对象本身:

      all_places = Place.objects(foo=bar)
      for p in all_places:
          place_json = json.dumps(p, cls=MongoEncoder)
      

      显示 to_dict 方法的版本。在 models.py 上:

      class Place(Document):
          name           = StringField()
          parent         = ReferenceField('self')
          ...
      
          def to_dict(self):
      
              return {
                  'id': str(self.id),
                  'parent': self.parent_id,
                  'name': self.name,
              }
      

      【讨论】:

      • obj 怎么有to_dict 方法?对我来说,这样的解决方案会引发 AttributeError。
      • 您好 Serge,在示例中,obj 是我称为 Place 的模型的一个实例。我正在编辑答案,以便向您展示如何创建 to_dict 方法。问候
      【解决方案3】:

      所以这是一个很老的问题。但我最近确实实施了一个解决方案。

      基本上,我在基础 Document 类上执行 to_json 方法所做的事情,但在编码器的默认方法本身中执行此操作。

      from json import JSONEncoder
      from bson.json_util import default
      from mongoengine import Document
      
      
      class MongoEncoder(JSONEncoder):
          def default(self, o):
              if isinstance(o, Document):
                  return o.to_mongo()
              return default(o)
      

      如果是 MongoEngine 文档,它会将其转换为 mongo 表示,然后将其中的每一部分传递给 MongoEngine 用来实现自己的 to_json 的 json_utils.default 函数。

      【讨论】:

        猜你喜欢
        • 2018-05-06
        • 1970-01-01
        • 2013-09-04
        • 2014-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多