我遇到了与Passing application context to custom converter using the Application Factory pattern类似的问题,我使用自定义网址转换器将Neo4j图形数据库ID转换为节点对象,即
import atexit
from flask import Flask
from neo4j.v1 import GraphDatabase
from werkzeug.routing import BaseConverter
class NodeConverter(BaseConverter):
def to_python(self, value):
with driver.session() as session:
cursor = session.run('MATCH (n {id: $id}) RETURN n', id=value)
return cursor.single().values()[0]
app = Flask(__name__)
app.url_map.converters['node'] = NodeConverter
driver = GraphDatabase.driver('bolt://localhost')
atexit.register(lambda driver=driver: driver.close())
@app.route('/<node:node>')
def test(node):
print node
if __name__ == '__main__':
app.run()
虽然这种方法利用单个数据库连接,但存在一些主要缺点:i)无法通过Flask配置配置数据库连接,以及ii)如果数据库失败,Flask应用程序也会失败。
为了解决这个问题,我按http://flask.pocoo.org/docs/0.12/extensiondev/创建了一个本地扩展名,即
from flask import _app_ctx_stack, Flask
from neo4j.v1 import GraphDatabase
from werkzeug.routing import BaseConverter
class MyGraphDatabase(object):
def __init__(self, app=None):
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
@app.teardown_appcontext
def teardown(exception):
ctx = _app_ctx_stack.top
if hasattr(ctx, 'driver'):
ctx.driver.close()
@property
def driver(self):
ctx = _app_ctx_stack.top
if ctx is not None and not hasattr(ctx, 'driver'):
ctx.driver = GraphDatabase.driver(app.config['NEO4J_URI'])
return ctx.driver
class NodeConverter(BaseConverter):
def to_python(self, value):
with app.app_context():
with db.driver.session() as session:
cursor = session.run('MATCH (n {id: $id}) RETURN n', id=value)
return cursor.single().values()[0]
db = MyGraphDatabase()
app = Flask(__name__)
app.config.from_pyfile('app.cfg')
app.url_map.converters['node'] = NodeConverter
db.init_app(app)
@app.route('/<node:node>')
def test(node):
print node
if __name__ == '__main__':
app.run()
这个问题是URL转换器在我需要包含以下块的应用程序上下文之外,
with app.app_context():
...
在URL解析期间创建临时应用程序上下文,然后立即丢弃,从性能角度来看似乎不是最理想的。这是正确的方法吗?
此配置的另一个问题是,当转换器和应用程序驻留在不同的文件中时,需要认识到潜在的循环引用,因为NodeConverter
需要app
和app
注册NodeConverter
。