【问题标题】:object is not JSON serializable对象不是 JSON 可序列化的
【发布时间】:2012-07-02 01:59:16
【问题描述】:

我在使用 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 让我很头疼。

提前致谢!

【问题讨论】:

  • 我只想添加导致我出现此问题和解决方案的错误:TypeError: unhashable type: 'dict'

标签: python json mongodb flask pymongo


【解决方案1】:

@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]

helper 实用程序告诉json 如何处理自定义 mongodb 对象。

【讨论】:

  • 你可以看到我也在使用这个,我的问题是忘记遍历光标!不过谢谢:)
  • from pymongo import json_util 已被弃用。请改用from bson import json_util
【解决方案2】:

当您将db.units.find() 传递给response 时,您将pymongo.cursor.Cursor 对象传递给json.dumps ... 而json.dumps 不知道如何将其序列化为JSON。尝试通过迭代光标来获取实际对象以获取其结果:

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

【讨论】:

  • @YisraelDov - 你有和 OP 一样的设置吗?请注意,他使用的是json.dumps(obj, default=json_util.default),而不仅仅是json.dumps(obj)
  • 当我做db.units.find()[:] 它总是返回我一个游标对象。我最终只是循环并添加到一个数组中,然后它就起作用了。
  • 是的,看起来 API 已经改变了......我会更新我的答案。
【解决方案3】:
import json
from bson import json_util

docs_list  = list(db.units.find())
return json.dumps(docs_list, default=json_util.default)

【讨论】:

    【解决方案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)
    

    至于Cursor,需要先迭代获取文档。

    【讨论】:

      【解决方案5】:

      简答:它是一个光标对象。迭代它,你会得到 python dicts。再次序列化:

      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

      【讨论】:

        【解决方案6】:

        以防万一您正在寻找一种更简单的 python 发送响应的方式,然后创建一个空列表并在其中附加值,最后以 JSON 格式返回此列表。

        from flask import Flask, jsonify
        
        @app.route('/view', methods=["GET'])
        def viewFun():
           data = units.find()
           s = []
           for i in data:
              s.append(str(i))
           return jsonify(s)
        

        可能不是完美的,但它有效!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-05-23
          • 2015-02-24
          • 2014-10-23
          • 1970-01-01
          • 1970-01-01
          • 2018-09-12
          • 2018-08-16
          • 2016-03-03
          相关资源
          最近更新 更多