2012-07-01 12 views
10

Ho qualche problema con Mongodb e Python (Flask).non è serializzabile JSON

Ho questo file api.py e desidero che tutte le richieste e le risposte siano in JSON, quindi lo implemento come tale.

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

Il problema qui è codifica dei dati JSON provenienti da e Mongo. Sembra che sia stato in grado di "hackerare" l'add route passando il request.json come dizionario per il salvataggio, quindi va bene ... il problema è/show. Questo codice non funziona ... Quando faccio qualche registrazione ottengo

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

Qualche idea? Accolgo anche eventuali suggerimenti sul resto del codice, ma il JSON mi sta uccidendo.

Grazie in anticipo!

+0

Voglio solo aggiungere l'errore che mi ha portato qui per questo problema e la soluzione: 'TypeError: Tipo di calcolo dell'hash: 'dict'' –

risposta

11

Quando si passa a db.units.find()response si passa un oggetto pymongo.cursor.Cursor-json.dumps ... e json.dumps non sa come serializzare a JSON. Prova ad ottenere gli oggetti reali scorrendo sopra il cursore per ottenere i suoi risultati:

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

Questo non sembra funzionare –

+0

@YisraelDov - avete lo stesso configurazione come l'OP? Nota che sta usando 'json.dumps (obj, default = json_util.default)', non solo 'json.dumps (obj)'. –

+0

quando faccio 'db.units.find() [:]' Mi restituisce sempre un oggetto cursore. Ho finito con il looping e l'aggiunta a un array, e poi ha funzionato. –

4

per codificare i documenti MongoDB a JSON, io uso un approccio simile a quello qui sotto che copre bson.objectid.ObjectId e datetime.datetime tipi.

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) 

Per quanto riguarda il cursore, è necessario iterarlo e ottenere i documenti prima.

26

Mentre @ ErenGüven mostra un buon approccio manuale per risolvere questo problema di serializzazione json, pymongo viene fornito con uno utility to accomplish this for you. Io uso questo nel mio progetto 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 semplicemente:

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

E per farli tornare da JSON ancora:

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

Le utilità di supporto dicono json come gestire gli oggetti mongodb personalizzati.

+0

puoi vedere che sto usando anche questo, il mio problema è stato dimenticare di scorrere il cursore! Grazie però :) – willium

+0

'da pymongo import json_util' è stato deprecato. Usa invece 'da bson import json_util'. – super9

+0

risolto. Grazie! – jdi

5
import json 
from bson import json_util 

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