Использование монго с FLASK и python
Я пытаюсь выучить python, mongodb и flask и использую ОЧЕНЬ ОТЛИЧНЫЙ блог от Мигеля Гринберга, который предоставляет большой набор руководств на blog.miguelgrinberg.com
Я получил небольшой RESTful сервер, работающий нормально, но теперь хочу вытащить вещи из Монго, а не 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 = ":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)
Любая помощь приветствуется, страница [0] это код, который просто не работает, я получаю
Ошибка типа: ObjectId('527e17c538320915e9893f17') не поддерживает сериализацию в формате JSON
заранее спасибо
КСТАТИ: Не могу порекомендовать мега-учебник Мигеля как место, где можно начать строить
3 ответа
Прежде всего find_one
вернет один словарь или 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'
)
редактировать
Если вам нужен короткий и грязный способ решения проблемы, вы можете сделать это так:
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))
Вы можете установить кодировщик по умолчанию:
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
Из того, что я вижу в вашем коде, видно, что вы не используете собственные идентификаторы Монго (которые хранятся в ключе _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
В качестве примечания, я думаю, что лучше не изобретать свои собственные идентификаторы, а просто использовать идентификаторы из Mongo.