Passing application context to custom converter using Application Factory template

I am currently creating an application that uses the Application Factory pattern . In this application, I have my own URL converter that takes an integer and returns an instance of the SQLAlchemy model with this identifier, if one exists. This works fine when I don't use the Application Factory pattern, but with this I get this error when accessing any route using the converter:

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

My application structure is as follows:

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? to_python with current_app.app_context(), , , 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
+4
2

. , "" , , , , , , factory pattern: . :

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-, .

: Major Gotcha: . ( , ). .

+1

, ( ) . decorator-

def swap_model(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        kwargs['some_model'] = SomeModel.query.filter(SomeModel.name == kwargs['some_model']).first()
        return func(*args, **kwargs)
    return decorated_function

route-

@main.route("<some_model>")
@swap_model
def get_some_model(some_model):
    return some_model.name

, 404 , present-

def swap_model(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        some_model = SomeModel.query.filter(SomeModel.name == kwargs['some_model']).first()
        if not some_model:
            abort(404)
        kwargs['some_model'] = some_model
        return func(*args, **kwargs)
    return decorated_function
0

Source: https://habr.com/ru/post/1616947/


All Articles