2012-07-01 107 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编码来自和来自mongo的数据。看来我已经能够通过传递request.json作为保存字典来“破解”添加路由,所以这很好...问题是/ show。此代码不起作用...当我做一些日志记录我得到

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

任何想法?我也欢迎其他代码的任何建议,但JSON正在杀死我。

在此先感谢!

+0

我只想补充一点,使我在这里对这个问题和解决方案的错误:'类型错误: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.ObjectIddatetime.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。我在我自己的Django 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

'从pymongo进口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) 
相关问题