2013-11-09 3 views
6

Я пытаюсь узнать питон, MongoDB и флягу и использую прекраснейший блог от Miguel Гринберга, который предоставляет большой набор учебных пособий по blog.miguelgrinberg.comИспользования Монго с колбой и питоном

Я получил небольшие RESTful сервер работает нормально, но теперь хочу вытащить материал из mongo, а не mysql

Я могу вытащить запись монго с помощью кода ниже, но я изо всех сил стараюсь его визуализировать.

Я использовал стрелки в коде ниже, чтобы показать, где я боюсь, недостаток опыта, я думаю. Любые мысли были бы оценены.

#!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 = ":[email protected]" 
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) 

Любая помощь приветствуется, страница [0] является код, который просто не работает, я получаю

TypeError: ObjectId ('527e17c538320915e9893f17') не JSON сериализации

Заранее спасибо

BTW Нельзя рекомендовать мега-учебник Мигеля как место для начала строительства

+0

Это поздно, но вы можете посмотреть на https://github.com/Bleezworld/ flask_skeleton, это скелет веб-сайта mongodb/Flask с некоторыми примерами использования (логин пользователя и т. д.) – Thomas

ответ

11

Прежде всего find_one вернет грех gle или None, если в коллекции нет соответствующего элемента. Так что я думаю, что page[0] эквивалентно получения значения словаря страницы для ключа 0

Если возвращаемые документы содержат ObjectId, как _id вы не можете просто использовать jsonify, потому что, как ObjectId не JSON сериализации. Вы можете использовать что-то вроде этого:

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

или вы можете просто удалить _id по телефону page.pop('_id')

Вы также можете использовать bson.json_util. Он содержит инструменты для преобразования между BSON и JSON.

from flask import Response 
from bson import json_util 

А потом заменить jsonify что-то похожее на это:

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

Edit

Если вы хотите короткий и грязный путь решения этой проблемы вы можете сделать это следующим образом:

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)) 
+0

Спасибо sero-use your page.pop ('_ id') похоже, что это поможет в сочетании с объяснением Miguels. Спасибо, что нашли время ответить. У меня не хватает репутации для продвижения этого ответа, но когда я сделаю – Richard

+0

Я опубликовал редактирование с альтернативным способом решения этой проблемы. Это не очень элегантно, но эффективно. – zero323

1

Fro m, что я вижу в вашем коде, кажется, вы не используете собственные идентификаторы Mongo (которые хранятся в ключе _id), но вместо этого вы генерируете свои собственные идентификаторы целого числа, которые вы храните в ключе id. Это верно?

Проблема с вашим кодом заключается в том, что ключ Mongo _id находится в объектах dict, которые вы отправляете в make_public_page(), и они не могут быть сериализованы для JSON.

Вы можете решить эту проблему, пропуская ключ _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 

Как примечание стороны, я считаю, что лучше не изобретать свои собственные идентификаторы и использовать только те из Монго.

+0

Да, вы правы, я несу свой собственный идентификатор, очень новый для монго и nosql, так что все еще на крутой части кривой обучения. хороший совет по использованию native _id и никогда бы не понял, что он не смог преобразовать значение mongo. Огромное спасибо, что я буду настаивать завтра. – Richard

2

можно установить кодировщик по умолчанию:

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) 

или вы можете создать подкласс json.encoder.JSONEncoder

Смежные вопросы