I am currently building an application that uses the Application Factory pattern. In this application, I have a custom URL converter, that takes an integer and returns an SQLAlchemy model instance with that ID, if it exists. This works fine when I'm not using the Application Factory pattern, but with it, I get this error when accessing any route that uses the converter:
RuntimeError: application not registered on db instance and no application bound to current context
My application structure looks like this:
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
Is there any way to somehow pass the application context to the CustomConverter? I have tried wrapping the contents of the to_python method with with current_app.app_context(), but all that does is reduce the error to RuntimeError: working outside of application context.
Here is the full traceback:
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
I just had the same problem. I'm not sure what the 'correct' way to solve it is, since this seems to be a rather obvious thing to do and should just work, but I solved it with the generic workaround that works for most problems with the application factory pattern: save the app object in a closure and inject it from outside. For your example:
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
Obviously this is rather less then elegant or optimal: A temporary app context is created during URL parsing and then discarded immediately.
EDIT: Major Gotcha: This does not work for non-trivial cases. The object returned will not be connected to a live session (the session is cleaned up when the temporary app context is closed). Modification and lazy loading will break.
The other solution is nice but (as it mentioned) presents a lot of problems. A more robust solution is to take a different approach and use a 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
Then for your route-
#main.route("<some_model>")
#swap_model
def get_some_model(some_model):
return some_model.name
You can even expand that by adding 404 errors when the model isn't 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
Related
I am trying to write tests to cover most of the functionality of a website I am building, but I keep getting the following error while running my tests.
Traceback (most recent call last):
File "tests.py", line 291, in test_delete_post_page_li
response = c.get('/delete_post/1', follow_redirects=True)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/werkzeug/test.py", line 1006, in get
return self.open(*args, **kw)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/testing.py", line 227, in open
follow_redirects=follow_redirects,
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/werkzeug/test.py", line 970, in open
response = self.run_wsgi_app(environ.copy(), buffered=buffered)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/werkzeug/test.py", line 861, in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/werkzeug/test.py", line 1096, in run_wsgi_app
app_rv = app(environ, start_response)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/kody/Projects/lifeLongLearning/app/blogs/views.py", line 182, in delete_post
db_session.delete(post)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/sqlalchemy/orm/scoping.py", line 162, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2018, in delete
self._delete_impl(state, instance, head=True)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2030, in _delete_impl
to_attach = self._before_attach(state, obj)
File "/home/kody/Projects/lifeLongLearning/venv/lib/python3.6/site-packages/sqlalchemy/orm/session.py", line 2417, in _before_attach
% (state_str(state), state.session_id, self.hash_key)
sqlalchemy.exc.InvalidRequestError: Object '<Post at 0x7fa75bb2ec50>' is already attached to session '19' (this is '4')
The tests code is:
class LoggedDatabaseTests(TestCase):
############################
#### setup and teardown ####
############################
def create_app(self):
app.config.from_object('config.TestConfiguration')
return app
# executed prior to each test
def setUp(self):
self.engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
self.db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=self.engine))
Base.query = self.db_session.query_property()
Base.metadata.create_all(bind=self.engine)
# executed after each test
def tearDown(self):
self.db_session.close()
self.db_session.remove()
self.db_session.rollback()
Base.metadata.drop_all(self.engine)
def test_delete_post_page_li(self):
p_cat = PostCategory(name='froots')
self.db_session.add(p_cat)
self.db_session.commit()
post = Post(name='Hello', content='3fhskajlga', category_id=1, category=p_cat)
self.db_session.add(post)
self.db_session.commit()
with app.test_client() as c :
login(c, '*****', '*****')
response = c.get('/delete_post/1', follow_redirects=True)
self.assertEqual(response.status_code, 302)
assert post not in self.db_session
The db_session mentioned in the test code is not the same db_session in the delete post view.
The code for the login function is:
def login(client, username, password):
return client.post('/login', data=dict(
username=username,
password=password
), follow_redirects=True)
The login view is:
#auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
if check_password_hash(passwrd, form.password.data) and form.username.data == 'LLLRocks':
session['logged_in'] = True
return redirect(url_for('other.home'))
# load login template
return render_template('login.html', form=form, title='Login')
The delete view is:
#
# Delete Post
# Description:
# This is a view that will delete a post. The id that is passed in is that of the
# post that will be deleted.
#
#blogs.route('/delete_post/<int:id>', methods=['GET', 'POST'])
def delete_post(id):
"""
Delete a post from the database
"""
# check if user is logged in
if not session.get('logged_in'):
return redirect(url_for('other.home'))
post = Post.query.get(id)
db_session.delete(post)
db_session.commit()
db_session.close()
db_session.remove()
db_session.rollback()
# redirect to the home page
return redirect(url_for('other.home'))
The database.py file is below. The db_session from this file is the db_session mentioned in the delete_post view.
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# Need to connect to the new database
engine = create_engine('mysql+mysqldb://****:******#******/****', convert_unicode=True, pool_recycle=3600, pool_pre_ping=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
import app.models
Base.metadata.create_all(bind=engine)
One of these days I will dive deep into the documentation, but until then sorry for my ignorance. If I have missed posting any important code please tell me and I will post it right away.
I have been able to get the code working and below I will post about how I was able to get it to work.
The test code now looks like the following.
from app.database import db
from config import TestConfiguration
from app import create_app as c_app
class TestingWhileLoggedIn(TestCase):
def create_app(self):
app = c_app(TestConfiguration)
return app
# executed prior to each test
def setUp(self):
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
login(self.client, 'LLLRocks', 'h0ngk0ng')
# executed after each test
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
logout(self.client)
def test_delete_post_page_li(self):
p_cat = PostCategory(name='froots')
db.session.add(p_cat)
db.session.commit()
post = Post(name='Hello', content='3fhskajlga', category_id=1, category=p_cat)
db.session.add(post)
db.session.commit()
response = self.client.get('/delete_post/1', follow_redirects=False)
self.assertEqual(response.status_code, 302)
deleted_post = Post.query.filter_by(name='Hello').first()
self.assertEqual(deleted_post, None)
assert post not in db.session
The config file now looks like
import os
from os.path import abspath, dirname, join
# _cwd = dirname(abspath(__file__))
_basedir = os.path.abspath(os.path.dirname(__file__))
TOP_LEVEL_DIR = os.path.abspath(os.curdir)
class Config(object) :
pass
class BaseConfiguration(object):
SQLALCHEMY_TRACK_MODIFICATIONS = False
class ProductionConfiguration(BaseConfiguration):
SQLALCHEMY_DATABASE_URI = '***************'
SQLALCHEMY_POOL_PRE_PING = True
SQLALCHEMY_ENGINE_OPTIONS = {'pool_recycle' : 3600}
SECRET_KEY = '************'
UPLOAD_FOLDER = TOP_LEVEL_DIR + '/app/static'
class TestConfiguration(BaseConfiguration):
TESTING = True
WTF_CSRF_ENABLED = False
SECRET_KEY = '************'
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(_basedir, 'testing.sqlite')
The database.py file is as follows
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
and the create_app function being imported is
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)#blogs.route('/delete_post/<int:id>', methods=['GET', 'POST'])
def delete_post(id):
"""
Delete a post from the database
"""
# check if user is logged in
if not session.get('logged_in'):
return redirect(url_for('other.home'))
post = Post.query.get(id)
db.session.delete(post)
db.session.commit()
# redirect to the home page
return redirect(url_for('other.home'))
from app import models
from .blogs import blogs as blogs_blueprint
app.register_blueprint(blogs_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
from .other import other as other_blueprint
app.register_blueprint(other_blueprint)
from .worksheets import worksheets as worksheets_blueprint
app.register_blueprint(worksheets_blueprint)
#app.teardown_appcontext
def shutdown_session(exception=None):
db.session.close()
db.session.remove()
db.session.rollback()
return app
The view being tested is as follows
#blogs.route('/delete_post/<int:id>', methods=['GET', 'POST'])
def delete_post(id):
"""
Delete a post from the database
"""
# check if user is logged in
if not session.get('logged_in'):
return redirect(url_for('other.home'))
post = Post.query.get(id)
db.session.delete(post)
db.session.commit()
# redirect to the home page
return redirect(url_for('other.home'))
The changes that were made from the code in the question is as follows.
db_session was replaced with db.session
The database.py file was made to only initiate a blank Flask-SQLAlchemy instance
The setup of the tests were made to use the create_app function defined in init. The testing configuration was passed to it so it uses the test database. Then the db.drop_all and db.create_all Flask-SQLAlchemy functions were used to create and clean out the database.
The login and logout was added to the setup and teardown for the tests but that is unrelated to the original question.
What fixed the problem was to change the code to use Flask-SQLAlchemy instead of only SQLAlchemy.
I'm programming a Website with Authentification while using the Flask Framework. I've tried every solution that i found on the internet but nothing worked for me.
My first idea was, that the Project Structure was corrupt. e.g. missing imports from other files. But thats not the problem i think.
My models.py File:
from flask_login import UserMixin, LoginManager
from flaskapp import db, login_manager
#login_manager.user_loader
def get_user(user):
try:
return get_id(user)
except:
return None
class User(db.Model,UserMixin):
id =db.Column(db.Integer, primary_key=True)
username =db.Column(db.String(20),unique=True, nullable=False)
email =db.Column(db.String(120), unique=True, nullable=False)
password =db.Column(db.String(60), nullable=False)
powerlevel =db.Column(db.Integer, nullable=False)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return int(self.id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.powerlevel}')"
My init.py File:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'xxx'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
login_manager = login_message_category = 'info'
from flaskapp import routes
When running the WebApp using:
export FLASK_APP=run.py DEBUG=TRUE
flask run
Following Error Message Occurs:
Traceback (most recent call last):
File "/home/osboxes/.local/bin/flask", line 11, in <module>
sys.exit(main())
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 966, in main
cli.main(prog_name="python -m flask" if as_module else None)
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 586, in main
return super(FlaskGroup, self).main(*args, **kwargs)
File "/home/osboxes/.local/lib/python3.6/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/home/osboxes/.local/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/osboxes/.local/lib/python3.6/site-packages/click/core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/osboxes/.local/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/home/osboxes/.local/lib/python3.6/site-packages/click/decorators.py", line 64, in new_func
return ctx.invoke(f, obj, *args, **kwargs)
File "/home/osboxes/.local/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 848, in run_command
app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 305, in __init__
self._load_unlocked()
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 330, in _load_unlocked
self._app = rv = self.loader()
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 388, in load_app
app = locate_app(self, import_name, name)
File "/home/osboxes/.local/lib/python3.6/site-packages/flask/cli.py", line 240, in locate_app
__import__(module_name)
File "/home/osboxes/Desktop/HMI/run.py", line 1, in <module>
from flaskapp import app
File "/home/osboxes/Desktop/HMI/flaskapp/__init__.py", line 21, in <module>
from flaskapp import routes
File "/home/osboxes/Desktop/HMI/flaskapp/routes.py", line 6, in <module>
from flaskapp.models import User
File "/home/osboxes/Desktop/HMI/flaskapp/models.py", line 7, in <module>
#login_manager.user_loader
AttributeError: 'str' object has no attribute 'user_loader'
Right now i don't know what else could be the problem.
If i forgot to supply some code for solving the error, let me know.
Thank you for your Help!
First, your User.get_id should be returning unicode not an int. The documentation mentions this, along with an example:
This method must return a unicode that uniquely identifies this user,
and can be used to load the user from the user_loader callback. Note
that this must be a unicode - if the ID is natively an int or some
other type, you will need to convert it to unicode. (Your User
Class)
So that needs to be changed to:
def get_id(self):
return unicode(self.id)
Next up, your user_loader. From the docs:
This sets the callback for reloading a user from the session. The
function you set should take a user ID (a unicode) and return a user
object, or None if the user does not exist.
Which would mean adjusting your user_loader to be something like:
#login_manager.user_loader
def get_user(user_id):
try:
return User.query.get(int(user_id))
except:
return None
Also, you have an error here, which is likely the direct cause of the error:
login_manager = login_message_category = 'info'
So your taking your login_manager and replacing it with a string with the contents 'info'. So later when your app tries to access login_manager.user_loader it's failing, because a string 'info' doesn't have a user_loader method.
Changing it to the below should fix the error. Though the other issues addressed above also need to be implemented.
login_manager.login_message_category = 'info'
You have used the login_manager = LoginManager(app) you are creating an object along with the configuration. Insider of that create an object first and configure the object in 2 steps.
login_manager = LoginManager()
login_manager.init_app(app)
for more reference please check the link here[https://flask-login.readthedocs.io/en/latest/]
you may need to update in your init.py file.
Getting the following error running a celery task, even with a Flask application context:
raised unexpected: RuntimeError('Working outside of application context.\n\nThis typically means that you attempted to use functionality that needed\nto interface with the current application object in some way. To solve\nthis, set up an application context with app.app_context(). See the\ndocumentation for more information.',)
Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/celery/app/trace.py", line 382, in trace_task
R = retval = fun(*args, **kwargs)
File "/usr/lib/python3.6/site-packages/celery/app/trace.py", line 641, in __protected_call__
return self.run(*args, **kwargs)
File "/app/example.py", line 172, in start_push_task
}, data=data)
File "/app/push.py", line 65, in push
if user and not g.get('in_celery_task') and 'got_user' not in g:
File "/usr/lib/python3.6/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/usr/lib/python3.6/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/usr/lib/python3.6/site-packages/flask/globals.py", line 44, in _lookup_app_object
raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
Any way to fix this?
For me, the issue was that I had import celery instead of from app import celery.
Here's some more of my setup code for anyone who stumbles across here in the future:
app.py
def make_celery(app):
app.config['broker_url'] = 'amqp://rabbitmq:rabbitmq#rabbit:5672/'
app.config['result_backend'] = 'rpc://rabbitmq:rabbitmq#rabbit:5672/'
celery = Celery(app.import_name, backend=app.config['result_backend'], broker=app.config['broker_url'])
celery.conf.update(app.config)
class ContextTask(Task):
abstract = True
def __call__(self, *args, **kwargs):
with app.test_request_context():
g.in_celery_task = True
res = self.run(*args, **kwargs)
return res
celery.Task = ContextTask
celery.config_from_object(__name__)
celery.conf.timezone = 'UTC'
return celery
celery = make_celery(app)
In the other file:
from app import celery
I am trying to write a class, ChangeBackStatusOnErrorTask which does exactly as its name implies.
class ChangeBackStatusOnErrorTask(Task):
abstract = True
def on_failure(self, exc, task_id, args, kwargs, einfo):
server = Server.query.get(server_id)
server.status = RemoteStatus.ERROR
db.session.commit()
#celery.task(bind=True, base=ChangeBackStatusOnErrorTask)
def deploy_server(self, server_id):
try:
server.status = RemoteStatus.LAUNCHING
db.session.commit()
host = server.ssh_user + '#' + server.ip
execute(fabric_deploy_server, self, server, hosts=host)
server.status = RemoteStatus.LAUNCHED
db.session.commit()
except Exception as e:
server.status = RemoteStatus.ERROR
db.session.commit()
traceback.print_exc()
raise e
However, this code is not working due to the fact that ChangeBackStatusOnErrorTask is not bounded to my Flask context:
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/celery/app/trace.py", line 367, in trace_task
R = retval = fun(*args, **kwargs)
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/celery/app/trace.py", line 622, in __protected_call__
return self.run(*args, **kwargs)
File "/Users/vng/Dropbox/Code/Affiliate/AutomataHeroku/automata/server/tasks.py", line 59, in deploy_server
server = Server.query.get(server_id)
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 498, in __get__
return type.query_class(mapper, session=self.sa.session())
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 78, in __call__
return self.registry()
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/util/_collections.py", line 990, in __call__
return self.registry.setdefault(key, self.createfunc())
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2861, in __call__
return self.class_(**local_kw)
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 143, in __init__
self.app = app = db.get_app()
File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py", line 957, in get_app
'application not registered on db instance and no application'
RuntimeError: application not registered on db instance and no application bound to current context
How can I fix this?
I will assume that you use sqlachemy and the flask-sqlalchemy extension. And that you get your db object from some dedicated module and this object is also bound to the flask instance(please edit your question to clarify those point).
Inside your app module declare your celery config:
app = Flask(__name__)
app.config[CELERY_BROKER_URL] = 'redis://localhost:6379'
app.config[CELERY_RESULT_BACKEND] = 'redis://localhost:6379'
Then inside your celery module you need to bound it to flask:
from celery import Celery
from app import current_app as app
def bound_celery(app):
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.conf.update(app.config)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
celery = bound_celery(app)
And finally use the celery created object to decorate your tasks:
#celery.task(bind=True, base=ChangeBackStatusOnErrorTask)
def deploy_server(self, server_id):
...
Source: flask doc
I'm debugging an error, when I try to query from my database to populate the fields of my FlaskForm, I get the following error:
Traceback (most recent call last):
File "manage.py", line 16, in <module>
app = create_app(os.getenv('DVR_CONFIG') or 'default')
File "C:\Users\---\myapp\\app\__init__.py", line 42, in create_app
from .main import main as main_blueprint
File "C:\Users\---\myapp\\app\main\__init__.py", line 5, in <module>
from . import views, errors
File "C:\Users\---\myapp\\app\main\views.py", line 5, in <module>
from .forms import CharacterSelect
File "C:\Users\---\myapp\\app\main\forms.py", line 15, in <module>
class CharacterSelect(FlaskForm):
File "C:\Users\---\myapp\\app\main\forms.py", line 17, in CharacterSelect
user = User.query.filter_by(unique_name=session.get('unique_name')).first()
File "C:\Python27\lib\site-packages\flask_sqlalchemy\__init__.py", line 500, in __get__
return type.query_class(mapper, session=self.sa.session())
File "C:\Python27\lib\site-packages\sqlalchemy\orm\scoping.py", line 78, in __call__
return self.registry()
File "C:\Python27\lib\site-packages\sqlalchemy\util\_collections.py", line 990, in __call__
return self.registry.setdefault(key, self.createfunc())
File "C:\Python27\lib\site-packages\flask_sqlalchemy\__init__.py", line 771, in create_session
return SignallingSession(self, **options)
File "C:\Python27\lib\site-packages\flask_sqlalchemy\__init__.py", line 153, in __init__
self.app = app = db.get_app()
File "C:\Python27\lib\site-packages\flask_sqlalchemy\__init__.py", line 922, in get_app
raise RuntimeError('application not registered on db '
RuntimeError: application not registered on db instance and no application bound to current context
Here is the offending code:
from ..models import User
class CharacterSelect(FlaskForm):
user = User.query.filter_by(unique_name=session.get('unique_name')).first()
charId0 = user.characterId_0
charId1 = user.characterId_1
charId2 = user.characterId_2
user_list = [charId0, 'Char0', charId1, 'Char1', charId2, 'Char2']
new_user_list = [x for x in user_list if x is not None]
selectedUser = SelectField(u'Character Select', choices=user_list)
From researching this error, it appears Flask doesn't know which app my DB is attached to. Also most of the stackoverflow answers I have seen recommend using:
with app.app_context():
:
:
db.create_all()
However, from working through Miguels Flask Book and Flasky blog, he doesn't seem to need to use "with app.app_context()" and only uses "db.create_all()" in his unit test code. Miguel inits the DB like so:
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
:
:
db.init_app(app)
Any help in debugging and understanding this error is much appreciated!
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
return app
Many things are nor clear from your code snippet. What is obvious however is that you have to have your db.init_app(app) inside your create_app() function. Then you would return app object from the function. Most preferably in different module i.e. manage.py (this really depends on your application structure)
from somewhere import create_app
app = create_app(config_name)
if __name__ == "__main__":
app.run()
Now variable app is your application instance with db registered.
Someone has pointed me to the FlaskForm Docs, where the is a pretty sparse example.
Esentially I need to create the tuple list in my views.py and pass it into my Form Object, see below for details:
views.py:
user = g.user
charId0 = user.characterId_0
charId1 = user.characterId_1
charId2 = user.characterId_2
user_list = [(charId0, 'Char0'), (charId1, 'Char1'), (charId2, 'Char2')]
form = CharacterSelect(request.form)
form.selectedUser.choices = user_list
forms.py:
class CharacterSelect(FlaskForm):
selectedUser = SelectField(u'Character Select', choices=[])