2012-07-01 53 views
10

Tôi đang gặp một số vấn đề với Mongodb và Python (Flask).đối tượng không phải là JSON serializable

Tôi có tệp api.py này và tôi muốn tất cả các yêu cầu và câu trả lời đều bằng JSON, vì vậy tôi thực hiện như vậy.

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

Vấn đề ở đây là dữ liệu mã hóa json đến và đi từ mongo. Có vẻ như tôi đã có thể "hack" các tuyến đường thêm bằng cách chuyển request.json làm từ điển để lưu, vì vậy thats tốt ... vấn đề là/hiển thị. Mã này không hoạt động ... Khi tôi đăng nhập, tôi nhận được

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

Bất kỳ ý tưởng nào? Tôi cũng hoan nghênh mọi đề xuất về phần còn lại của mã, nhưng JSON đang giết tôi.

Cảm ơn trước!

+0

Tôi chỉ muốn thêm lỗi mà dẫn tôi ở đây cho câu hỏi này và giải pháp: 'Lỗi Loại: unhashable loại: 'dict'' –

Trả lời

11

Khi bạn vượt qua db.units.find() để response bạn vượt qua một đối tượng pymongo.cursor.Cursor-json.dumps ... và json.dumps không biết làm thế nào để serialize nó để JSON. Hãy thử lấy các đối tượng thực tế bằng cách duyệt qua các con trỏ để có được kết quả của nó:

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

này dường như không làm việc –

+0

@YisraelDov - làm bạn có cùng thiết lập như OP? Lưu ý rằng anh ta đang sử dụng 'json.dumps (obj, default = json_util.default)', không chỉ 'json.dumps (obj)'. –

+0

khi tôi làm 'db.units.find() [:]' Nó luôn trả về cho tôi một đối tượng con trỏ. Tôi đã kết thúc chỉ lặp lại và thêm vào một mảng, và sau đó nó làm việc. –

4

Để mã hóa các tài liệu MongoDB để JSON, tôi sử dụng một cách tiếp cận tương tự như hình dưới đây bao gồm bson.objectid.ObjectIddatetime.datetime loại.

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) 

Đối với con trỏ, bạn cần phải lặp lại và nhận tài liệu trước.

26

Trong khi @ ErenGüven cho bạn thấy một cách tiếp cận thủ công tốt đẹp để giải quyết vấn đề tuần tự json này, pymongo đi kèm với utility to accomplish this for you. Tôi sử dụng này trong dự án django MongoDB của riêng tôi:

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) 

Hoặc đơn giản là:

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

Và để có được chúng trở lại từ json một lần nữa:

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

Các tiện ích helper nói json làm thế nào để xử lý các đối tượng mongodb tùy chỉnh.

+0

bạn có thể thấy tôi đang sử dụng quá, vấn đề của tôi đã quên để lặp qua con trỏ! Cảm ơn mặc dù :) – willium

+0

'từ pymongo import json_util' đã không được chấp nhận. Sử dụng 'từ bson import json_util' để thay thế. – super9

+0

Đã sửa lỗi. Cảm ơn! – jdi

5
import json 
from bson import json_util 

docs_list = list(db.units.find()) 
return json.dumps(docs_list, default=json_util.default) 
Các vấn đề liên quan