11

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

Flask 0.10.1 中似乎有与 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

4 回答 4

13

编辑:更容易修复。您甚至不需要进行任何 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

于 2013-07-16T04:21:30.220 回答
12

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

您可能需要稍微调整此代码,但对于传递的简单情况

于 2013-07-15T08:14:10.653 回答
0

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

@app.route('/')
def home():
    docs = []
    for doc in db.person.find():
        doc.pop('_id') 
        docs.append(doc)
    return jsonify(docs)
于 2017-02-06T01:17:24.030 回答
0

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

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

选择 session['_id'] = str(user['_id'])

以上为我修复了错误。

于 2017-05-10T23:20:23.687 回答