Utilisation de mongo avec flacon et python

j'essaie d'apprendre python, mongodb et flask et j'utilise le Très EXCELLENT blog de Miguel Grinberg qui fournit un grand ensemble de tutoriels à blog.miguelgrinberg.com

j'ai un petit serveur de repos qui fonctionne bien, mais maintenant je veux tirer des trucs de mongo pas mysql

je peux extraire un enregistrement de mongo en utilisant le code ci-dessous mais j'ai du mal à le rendre.

j'ai utilisé des flèches dans le code ci-dessous pour afficher là où je me bats, le manque d'expérience je pense. Toute pensée serait appréciée.

#!flask/bin/python
from flask import Flask, jsonify, abort, make_response, url_for
from pymongo import MongoClient

# connect to mongo database hosted on AWS
# the script expects the host name to be in  /etc/hosts file

'''
Set up global variables here
'''
mongo_server = "mongo_api"
mongo_port = "27017"
mongo_user = "admin"
mongo_passwd = ":mysecretpassword@"
connect_string = "mongodb://"+ mongo_user 
                             + mongo_passwd 
                             + mongo_server 
                             + ":" 
                             + mongo_port

app = Flask(__name__)

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify( { 'error': 'Notfound' } ), 404)


def make_public_page(page):
    new_page = {}
    for field in page:
        if field == 'id':
            new_page['uri'] = url_for('get_page', page_id = page['id'], _external = True)
        else:
            new_page[field] = page[field]
    return new_page



@app.route('/api/v1.0/pages/<int:page_id>',methods = ['GET'])
def get_page(page_id):
    '''
    Can connect otherwise exit with message
    '''
    try:
        connection = MongoClient(connect_string)    # equal to > show dbs
    except:
        exit("Error: Unable to connect to the database") # exit with an error
    '''
    connect to database and pull back collections
    '''
    db = connection.test_database # equal to > use test_database                
    pages = db.pages
    page = pages.find_one({"id": int(page_id)})   <------ this pulls back a document
    if page == None:  <---- if a null set comes back then this works great
        abort(404)
    return jsonify( { 'page' : make_public_page(page[0])} ) <- error says its not json

if __name__ == '__main__':
    app.run(debug = True)

toute aide appréciée, page[0] est le code qui ne fonctionne pas je reçois un

TypeError: ObjectId ('527e17c538320915e9893f17') is not JSON serializable

Merci d'avance

BTW ne peut pas recommander le tutoriel mega De Miguel assez comme un endroit pour commencer à construire des choses

6
demandé sur Richard 2013-11-09 19:54:32

3 réponses

tout d'Abord find_one sera de retour seul dictionnaire ou Aucun si il n'y a pas d'élément correspondant dans la collection. Donc je pense que page[0] est équivalent à obtenir la valeur du dictionnaire de la page pour la clé 0

si les documents retournés contiennent ObjectId comme _id vous ne pouvez pas simplement utiliser jsonify parce que, comme ObjectId n'est pas sérialisable JSON. Vous pouvez utiliser quelque chose comme ceci:

jsonify({ 'page': make_public_page({k:v for k, v in page.items() if k != '_id'}))

ou vous pouvez il suffit de supprimer _id en appelant page.pop('_id')

vous pouvez également utiliser bson.json_util . Il contient des outils pour la conversion entre BSON et JSON.

from flask import Response 
from bson import json_util

et remplacer jsonify par quelque chose de similaire:

return Response(
    json_util.dumps({'page' : make_public_page(page)}),
    mimetype='application/json'
)

Modifier

Si vous voulez court et sale manière de traiter le problème, vous pouvez le faire comme ceci:

from bson import json_util, ObjectId
import json

#Lets create some dummy document to prove it will work
page = {'foo': ObjectId(), 'bar': [ObjectId(), ObjectId()]}

#Dump loaded BSON to valid JSON string and reload it as dict
page_sanitized = json.loads(json_util.dumps(page))
11
répondu zero323 2013-11-09 19:49:26

vous pouvez définir l'encodeur par défaut:

import json
from bson.objectid import ObjectId

def newEncoder(o):
    if type(o) == ObjectId:
        return str(o)
    return o.__str__

....

return json.dumps(list(somecollection.find(expr)) ,  default=newEncoder )

ou vous pourriez classer json.encodeur.JSONEncoder

2
répondu enthus1ast 2014-07-06 15:20:29

D'après ce que je vois dans votre code, il semble que vous n'utilisez pas les propres IDs de Mongo (qui sont stockés dans la clé _id ), mais au lieu de cela vous générez vos propres IDs entiers, que vous stockez dans la clé id . Est-ce correct?

le problème avec votre code est que la clé Mongo _id est dans les objets dict que vous envoyez à make_public_page() , et ceux-ci ne peuvent pas être sérialisés à JSON.

, Vous pouvez résoudre ce problème en touche de saut _id :

def make_public_page(page):
    new_page = {}
    for field in page:
        if field == 'id':
            new_page['uri'] = url_for('get_page', page_id = page['id'], _external = True)
        elif field != '_id':
            new_page[field] = page[field]
    return new_page

comme note secondaire, je pense qu'il est préférable de ne pas inventer vos propres ID et juste utiliser ceux de Mongo.

1
répondu Miguel 2013-11-09 19:03:01