我在使用Mongodb和Python(Flask)时遇到了一些麻烦。
我有这个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()
这里的问题是来自mongo的json编码数据。看来我已经能够通过将request.json作为保存字典来“破解”添加路由,所以那很好......问题是/ show。这段代码不起作用......当我做一些日志记录时,我得到了
TypeError: <pymongo.cursor.Cursor object at 0x109bda150> is not JSON serializable
有什么想法吗?我也欢迎任何有关其余代码的建议,但是JSON正在杀了我。
提前致谢!
答案 0 :(得分:29)
虽然@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对象。
答案 1 :(得分:14)
当您将db.units.find()
传递给response
时,您将pymongo.cursor.Cursor
对象传递给json.dumps
... json.dumps
不知道如何将其序列化为JSON。尝试通过迭代光标来获取实际对象以获得结果:
[doc for doc in db.units.find()]
答案 2 :(得分:9)
import json
from bson import json_util
docs_list = list(db.units.find())
return json.dumps(docs_list, default=json_util.default)
答案 3 :(得分: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)
对于Cursor,您需要迭代它并首先获取文档。
答案 4 :(得分:0)
简短的回答:它是一个游标对象。对其进行迭代,您会得到python dict。再次进行序列化:
import json
from bson import json_util
让我们说这是我的查询:
details = mongo.db.details.find()
# this is cursor object
#iterate over to get a list of dicts
details_dicts = [doc for doc in details]
#serialize to json string
details_json_string = json.dumps(details_dicts,default=json_util.default)
如果您想返回上面的内容,它将只是一个字符串。执行此操作以将其返回为可用的dict或json
return json.loads(details_json_string)
#return jsonified version rather than string without unwanted "\" in earlier json string!
希望有帮助!祝您编码愉快!
如果您的查询中不包含Objectid等复杂的文件,可以使用普通的旧jsonify