2012-07-01 2 views
10

У меня проблемы с Mongodb и Python (Flask).объект не JSON сериализуемый

У меня есть этот файл api.py, и я хочу, чтобы все запросы и ответы были в JSON, поэтому я реализую как таковой.

# 
# Imports 
# 

from datetime import datetime 
from flask import Flask 
from flask import g 
from flask import jsonify 
from flask import json 
from flask import request 
from flask import url_for 
from flask import redirect 
from flask import render_template 
from flask import make_response 
import pymongo 
from pymongo import Connection 
from bson import BSON 
from bson import json_util 

# 
# App Create 
# 

app = Flask(__name__) 
app.config.from_object(__name__) 

# 
# Database 
# 

# connect 
connection = Connection() 
db = connection['storage'] 
units = db['storage'] 


# 
# Request Mixins 
# 

@app.before_request 
def before_request(): 
    #before 
    return 

@app.teardown_request 
def teardown_request(exception): 
    #after 
    return 


# 
# Functions 
# 

def isInt(n): 
    try: 
     num = int(n) 
     return True 
    except ValueError: 
     return False 

def isFloat(n): 
    try: 
     num = float(n) 
     return True 
    except ValueError: 
     return False 

def jd(obj): 
    return json.dumps(obj, default=json_util.default) 

def jl(obj): 
    return json.loads(obj, object_hook=json_util.object_hook) 

# 
# Response 
# 

def response(data={}, code=200): 
    resp = { 
     "code" : code, 
     "data" : data 
    } 
    response = make_response(jd(resp)) 
    response.headers['Status Code'] = resp['code'] 
    response.headers['Content-Type'] = "application/json" 
    return response 


# 
# REST API calls 
# 

# index 
@app.route('/') 
def index(): 
    return response() 

# search 
@app.route('/search', methods=['POST']) 
def search(): 
    return response() 

# add 
@app.route('/add', methods=['POST']) 
def add(): 
    unit = request.json 
    _id = units.save(unit) 
    return response(_id) 

# get 
@app.route('/show', methods=['GET']) 
def show(): 
    import pdb; pdb.set_trace(); 
    return response(db.units.find()) 

# 
# Error handing 
# 

@app.errorhandler(404) 
def page_not_found(error): 
    return response({},404) 


# 
# Run it! 
# 

if __name__ == '__main__': 
    app.debug = True 
    app.run() 

Проблема здесь - данные кодирования json, поступающие в и из монго. Кажется, я смог «взломать» маршрут добавления, передав request.json в качестве словаря для сохранения, так что это хорошо ... проблема/show. Этот код не работает ... Когда я делаю некоторые записи, я получаю

TypeError: <pymongo.cursor.Cursor object at 0x109bda150> is not JSON serializable 

Любые идеи? Я также приветствую любые предложения по остальной части кода, но JSON убивает меня.

Заранее благодарен!

+0

Я просто хочу, чтобы добавить ошибку, которая привела меня сюда на этот вопрос и решение: 'TypeError: unhashable типа:«dict'' –

ответ

11

Когда вы передаете db.units.find() к response вы передаете pymongo.cursor.Cursor объект json.dumps ... и json.dumps не знает, как сериализовать его JSON. Попробуйте получить фактические объекты итерируя над курсором, чтобы получить свои результаты:

[doc for doc in db.units.find()] 
+0

Это не похоже на работу –

+0

@YisraelDov - у вас есть то же самое настроить как OP? Обратите внимание, что он использует 'json.dumps (obj, default = json_util.default)', а не только 'json.dumps (obj)'. –

+0

когда я делаю 'db.units.find() [:]' Он всегда возвращает мне объект курсора. Я закончил, просто перешел в циферблат и добавил в массив, а затем он сработал. –

4

Для кодирования MongoDB документов в формат JSON, я использую подобный подход к тому, ниже которого охватывает bson.objectid.ObjectId и datetime.datetime типов.

class CustomEncoder(json.JSONEncoder): 
    """A C{json.JSONEncoder} subclass to encode documents that have fields of 
    type C{bson.objectid.ObjectId}, C{datetime.datetime} 
    """ 
    def default(self, obj): 
     if isinstance(obj, bson.objectid.ObjectId): 
      return str(obj) 
     elif isinstance(obj, datetime.datetime): 
      return obj.isoformat() 
     return json.JSONEncoder.default(self, obj) 

enc = CustomEncoder() 
enc.encode(doc) 

Что касается Курсора, вам необходимо выполнить итерацию и получить документы в первую очередь.

26

Хотя @ ErenGüven показывает вам хороший ручной подход к решению этой проблемы сериализации json, pymongo поставляется с utility to accomplish this for you. Я использую это в моем проекте Джанго MongoDB:

import json 
from bson import json_util 

json_docs = [] 
for doc in cursor: 
    json_doc = json.dumps(doc, default=json_util.default) 
    json_docs.append(json_doc) 

Или просто:

json_docs = [json.dumps(doc, default=json_util.default) for doc in cursor] 

И получить их обратно с JSON снова:

docs = [json.loads(j_doc, object_hook=json_util.object_hook) for j_doc in json_docs] 

Вспомогательные утилиты сказать json как обрабатывать пользовательские объекты mongodb.

+0

вы можете видеть, что я тоже использую это, моя проблема заключалась в том, чтобы забыть перебирать курсор! Спасибо, хотя :) – willium

+0

'from pymongo import json_util' устарел. Вместо этого используйте 'from bson import json_util'. – super9

+0

Исправлено. Благодаря! – jdi

5
import json 
from bson import json_util 

docs_list = list(db.units.find()) 
return json.dumps(docs_list, default=json_util.default) 
Смежные вопросы