使用Flask 0.10.1时,获取'TypeError:ObjectId('')不是JSON可序列化的'

时间:2013-07-13 23:11:59

标签: python json flask pymongo

我将Flask示例Minitwit与MongoDB一起使用,它在Flask 0.9上工作正常,但升级到0.10.1后,当我尝试设置会话ID时,我在登录时收到错误。< / p>

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

代码段:

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

我的github回购邮件中的完整代码。

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

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

好吧,做session ['_ id'] = str(user ['_ id'])摆脱错误信息,我已正确地重定向到时间线页面,但我实际上并没有登录。

我该如何解决这个问题?

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

谢谢。

4 个答案:

答案 0 :(得分:12)

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

只需将会话['_ 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上看到修补程序的完整差异。

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

答案 1 :(得分:10)

默认情况下,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

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

json.dumps(obj, cls=Encoder)

服务器端,如果我们知道我们正在处理mongo docs(带有'_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)

您可能需要对此代码进行一些调整,但是对于传递

的简单情况

答案 2 :(得分:0)

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

{{1}}

答案 3 :(得分:0)

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

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

替代     session['_id'] = str(user['_id'])

以上修正了我的错误。