Получение 'TypeError: ObjectId (' ') не является сериализуемым JSON' при использовании Flask 0.10.1

Я разработал пример Flask, Minitwit, для работы с MongoDB, и он отлично работал на Flask 0.9, но после обновления до 0.10.1 я получаю ошибку в заголовке при входе в систему, когда пытаюсь установить идентификатор сеанса.

Кажется, что изменяется в Flask 0.10.1, относящемся к json.

Фрагмент кода:

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

Полный код в моем github repo.

В принципе, я устанавливаю идентификатор сеанса Flask пользователю _id из MongoDB.

Я пробовал первые два решения из этого вопроса SO без успеха.

Ну, делая сеанс ['_ id'] = str (user ['_ id']) избавляется от сообщения об ошибке, и я правильно перенаправлен на страницу временной шкалы, но я фактически не вошел в систему.

Как я могу это исправить?

EDIT: копирование/вставка трассировки: http://pastebin.com/qa0AL1fk

Спасибо.

Ответ 1

EDIT: Еще проще исправить. Вам даже не нужно кодировать/декодировать JSON.

Просто сохраните сеанс ['_ id'] в виде строки:

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

И тогда, когда вы хотите что-то делать с сеансом ['_ 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'])})

Вы можете увидеть полный diff для исправления на моем github repo.

Если кто-то заботится о том, почему "TypeError: ObjectId ('') не является сериализуемым JSON" проблемой ", появившимся в Flask 0.10.1, это потому, что они изменили способ хранения сеансов. Теперь они хранятся как JSON, так как объект" _id "в MongoDB не является стандартным 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

Затем, в вашем коде, перед тем, как нажать клиентский клиент данных → server, запустите:

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'])

Вышеуказанная ошибка для меня.