Получение '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'])
Вышеуказанная ошибка для меня.