【问题标题】:Getting 'TypeError: ObjectId('') is not JSON serializable' when using Flask 0.10.1使用 Flask 0.10.1 时出现“TypeError: ObjectId('') is not JSON serializable'
【发布时间】:2013-07-12 04:23:04
【问题描述】:

我将 Flask 示例 Minitwit 用于 MongoDB,它在 Flask 0.9 上运行良好,但在升级到 0.10.1 后,当我尝试设置会话 id 时登录时出现标题错误。

Flask 0.10.1 中似乎有 changes 与 json 相关。

代码sn-p:

user = db.minitwit.user.find_one({'username': request.form['username']})
session['_id'] = user['_id']

完整代码在我的github repo 中。

基本上,我将 Flask 会话 ID 设置为 MongoDB 中用户的 _id。

我尝试了SO question 的前两个解决方案,但没有成功。

好吧,执行 session['_id'] = str(user['_id']) 可以消除错误消息,并且我已正确重定向到时间线页面,但我实际上并没有登录。

我该如何解决这个问题?

编辑:复制/粘贴回溯:http://pastebin.com/qa0AL1fk

谢谢。

【问题讨论】:

    标签: python json flask pymongo


    【解决方案1】:

    编辑:更容易修复。您甚至不需要进行任何 JSON 编码/解码。

    只需将 session['_id'] 保存为字符串:

    user = db.minitwit.user.find_one({'username': request.form['username']})
    session['_id'] = str(user['_id'])
    

    然后在任何你想对 session['_id'] 做某事的地方,你都必须用 ObjectId() 包装它,以便将它作为 ObjectId 对象传递给 MongoDB。

    if '_id' in session:
        g.user = db.minitwit.user.find_one({'_id': session['_id']})
    

    到:

    if '_id' in session:
        g.user = db.minitwit.user.find_one({'_id': ObjectId(session['_id'])})
    

    您可以在我的github repo 上查看修复的完整差异。

    如果有人想知道为什么 Flask 0.10.1 中出现“TypeError: ObjectId('') is not JSON serializable”“问题”,那是因为他们改变了会话的存储方式。它们现在存储为 JSON,因此由于 MongoDB 中的“_id”对象不是标准 JSON,它无法序列化会话令牌,从而产生 TypeError。在此处阅读更改:http://flask.pocoo.org/docs/upgrading/#upgrading-to-010

    【讨论】:

      【解决方案2】:

      默认情况下,JSON 仅支持序列化(编码/解码)一组有限的对象类型。不过,您可以扩展 python JSON 的解码器/编码器来处理这种情况。

      在对包含在 ObjectID 上的对象进行编码方面,例如,当在客户端创建 ObjectIds 时,它将被传递给某个等待的服务器,尝试:

      import json
      from bson.objectid import ObjectId
      
      class Encoder(json.JSONEncoder):
          def default(self, obj):
              if isinstance(obj, ObjectId):
                  return str(obj)
              else:
                  return obj
      

      然后,在您的代码中,在推送数据客户端 -> 服务器之前,运行:

      json.dumps(obj, cls=Encoder)
      

      服务器端,如果我们知道我们正在处理 mongo 文档(带有 '_id' 键的字典对象),我们可以定义一个 json 解码器挂钩,如下所示:

      def decoder(dct):
          for k, v in dct.items():
              if '_id' in dct:
                  try:
                      dct['_id'] = ObjectId(dct['_id'])
                  except:
                      pass
              return dct
      

      并使用如下调用来调用它:

      doc = json.loads(in_doc, object_hook=decoder)
      

      您可能需要稍微修改一下这段代码,但对于传递的简单情况

      【讨论】:

        【解决方案3】:

        这就是我最近修复错误的方法

        @app.route('/')
        def home():
            docs = []
            for doc in db.person.find():
                doc.pop('_id') 
                docs.append(doc)
            return jsonify(docs)
        

        【讨论】:

          【解决方案4】:

          toString 将其转换为字符串并可以存储到会话中:

          session['_id'] = user['_id'].toString()
          

          另类 session['_id'] = str(user['_id'])

          以上为我修复了错误。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-08-10
            • 2013-11-25
            • 2019-05-06
            • 2019-10-09
            • 2021-03-02
            • 2017-05-10
            • 2021-03-21
            相关资源
            最近更新 更多