2015-11-22 78 views
4

傳遞應用程序上下文來定製轉換器我目前正在建設一個使用Application Factory圖案的應用。在這種應用中,我有一個自定義URL轉換器,它接受一個整數,並使用該ID返回SQLAlchemy的模型實例,如果存在的話。當我不使用應用工廠模式也能正常工作,但有了它,我得到這個錯誤訪問使用該轉換器的任何路由時:使用應用工廠模式

RuntimeError: application not registered on db instance and no application bound to current context 

我的應用程序的結構是這樣的:

app/__init__.py

from flask import Flask 
from flask_sqlalchemy import SQLAlchemy 
from config import config 

db = SQLAlchemy() 

def create_app(config_name): 
    app = Flask(__name__) 
    app.config.from_object(config[config_name]) 
    db.init_app(app) 

    from app.converters import CustomConverter 
    app.url_map.converters["custom"] = CustomConverter 

    from app.views.main import main 
    app.register_blueprint(main) 
    return app 

app/converters.py

from werkzeug.routing import ValidationError, IntegerConverter 
from app.models import SomeModel 


class CustomConverter(IntegerConverter): 
    """ Converts a valid SomeModel ID into a SomeModel object. """ 
    def to_python(self, value): 
     some_model = SomeModel.query.get(value) 
     if some_model is None: 
      raise ValidationError() 
     else: 
      return some_model 

app/views/main.py

from flask import Blueprint 

main = Blueprint("main", __name__) 

# This causes the aforementioned error. 
@main.route("/<custom:some_model>") 
def get_some_model(some_model): 
    return some_model.name 

有沒有辦法以某種方式通過應用程序上下文的CustomConverter?我曾嘗試與with current_app.app_context()包裹to_python方法的內容,但所有這確實是錯誤減少到RuntimeError: working outside of application context

以下是完整的回溯:

File "c:\Python34\lib\site-packages\flask\app.py", line 1836, in __call__ 
return self.wsgi_app(environ, start_response) 
File "c:\Python34\lib\site-packages\flask\app.py", line 1812, in wsgi_app 
ctx = self.request_context(environ) 
File "c:\Python34\lib\site-packages\flask\app.py", line 1773, in request_context 
return RequestContext(self, environ) 
File "c:\Python34\lib\site-packages\flask\ctx.py", line 247, in __init__ 
self.match_request() 
File "c:\Python34\lib\site-packages\flask\ctx.py", line 286, in match_request 
self.url_adapter.match(return_rule=True) 
File "c:\Python34\lib\site-packages\werkzeug\routing.py", line 1440, in match 
rv = rule.match(path) 
File "c:\Python34\lib\site-packages\werkzeug\routing.py", line 715, in match 
value = self._converters[name].to_python(value) 
File "c:\Users\Encrylize\Desktop\Testing\Flask\app\converters.py", line 8, in to_python 
some_model = SomeModel.query.get(value) 
File "c:\Python34\lib\site-packages\flask_sqlalchemy\__init__.py", line 428, in __get__ 
return type.query_class(mapper, session=self.sa.session()) 
File "c:\Python34\lib\site-packages\sqlalchemy\orm\scoping.py", line 71, in __call__ 
return self.registry() 
File "c:\Python34\lib\site-packages\sqlalchemy\util\_collections.py", line 988, in __call__ 
return self.registry.setdefault(key, self.createfunc()) 
File "c:\Python34\lib\site-packages\flask_sqlalchemy\__init__.py", line 136, in __init__ 
self.app = db.get_app() 
File "c:\Python34\lib\site-packages\flask_sqlalchemy\__init__.py", line 809, in get_app 
raise RuntimeError('application not registered on db ' 
RuntimeError: application not registered on db instance and no application bound to current context 
+0

既然我們無法重現這個問題,也許詳細的日誌,而不只是一個行會更有幫助。 –

+0

嗯,registerring藍圖作品後編輯的轉換? –

+0

@ lord63.j,添加回溯到帖子。在藍圖註冊之後放置轉換器只會導致轉換器無法在該藍圖中工作。如果您想在藍圖中使用藍圖,則需要在註冊藍圖之前設置轉換器。 – Encrylize

回答

1

我有同樣的問題。我不知道什麼是「正確」的方式來解決它,因爲這似乎是做了相當明顯的事情,應該只是工作,但我對於大多數問題與應用工廠模式運作的通用解決方法解決它:將應用程序對象保存在閉包中並從外部注入。對於你的例子:

def converters(app): 
    class CustomConverter(IntegerConverter): 
     """ Converts a valid SomeModel ID into a SomeModel object. """ 
     def to_python(self, value): 
      with app.app_context(): 
       some_model = SomeModel.query.get(value) 
       if some_model is None: 
        raise ValidationError() 
       else: 
        return some_model 
    return {"custom": CustomConverter} 

def create_app(config_name): 
    app = Flask(__name__) 
    app.config.from_object(config[config_name]) 
    db.init_app(app) 

    app.url_map.converters.update(converters(app)) 

    from app.views.main import main 
    app.register_blueprint(main) 
    return app 

顯然,這是相當小於優雅或最佳:URL解析過程中創建的臨時應用程序上下文,然後立即丟棄。

編輯:主要問題:這是不是工作非平凡的情況。返回的對象不會連接到實時會話(當臨時應用程序上下文關閉時會話被清除)。修改和延遲加載將會中斷。

+0

您是否知道這個更優雅的解決方案,正如您指出的那樣,它會在URL解析過程中創建臨時應用上下文,而這在很多級別上都不是最理想的? – John