2012-07-01 123 views
10

Tengo algunos problemas con Mongodb y Python (Flask).objeto no es JSON serializable

Tengo este archivo api.py, y quiero que todas las solicitudes y respuestas estén en JSON, así que lo implemento como tal.

# 
# 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() 

El problema aquí es json datos de codificación procedentes de y desde mongo. Parece que he sido capaz de "piratear" la ruta de agregar pasando el request.json como el diccionario para guardar, así que eso es bueno ... el problema es/show. Este código no funciona ... Cuando hago algún registro consigo

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

¿Alguna idea? También recibo sugerencias sobre el resto del código, pero el JSON me está matando.

¡Gracias de antemano!

+0

sólo quiero añadir el error que me ha llevado aquí a esta pregunta y la solución: 'TypeError: Tipo unhashable: 'dict'' –

Respuesta

11

Cuando se pasa a db.units.find()response se pasa un objeto pymongo.cursor.Cursor a json.dumps ... y json.dumps no sabe cómo serializar a JSON. Trate de conseguir los objetos reales iterando sobre el cursor para obtener sus resultados:

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

Esto no parece funcionar –

+0

@YisraelDov - ¿tiene el mismo configurar como el OP? Tenga en cuenta que está usando 'json.dumps (obj, default = json_util.default)', no solo 'json.dumps (obj)'. –

+0

cuando hago 'db.units.find() [:]' Siempre me devuelve un objeto de cursor. Terminé simplemente yendo y añadiendo a una matriz, y luego funcionó. –

4

para codificar documentos MongoDB a JSON, utilizo un enfoque similar a la de abajo que cubre bson.objectid.ObjectId y datetime.datetime tipos.

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) 

En cuanto al Cursor, necesita repetirlo y obtener documentos primero.

26

Mientras @ ErenGüven le muestra un buen enfoque manual para resolver este problema de serialización json, pymongo viene con un utility to accomplish this for you. Yo uso este en mi propio proyecto 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) 

O simplemente:

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

Y para que vuelvan a JSON nuevo:

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

Las utilidades de ayuda dicen json cómo manejar los objetos mongodb personalizados.

+0

se puede ver que estoy usando esto también, mi problema fue olvidar repetir el cursor! Sin embargo, gracias :) – willium

+0

'from pymongo import json_util' ha quedado en desuso. Use 'from bson import json_util' en su lugar. – super9

+0

Solucionado. ¡Gracias! – jdi

5
import json 
from bson import json_util 

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