Each time you use the self-written CLI command, a call to app_context occurs, as a result of which extra Blueprint is connected, as well as loggers that are called when the project starts.
Is there any list or variable in which I can write from WHERE the call to app_context occurs.
__name__ is the same everywhere, always returns 'app'.
project.py:
from app import create_app, cli
app = create_app()
cli.register(app)
app/__init__.py:
db = SQLAlchemy()
migrate = Migrate()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db)
app.logger.setLevel(logging.INFO)
app.logger.info('Project startup')
return app
app.logger.info('Project startup') called every time when I'm calling CLI command.
What condition can be added for not call this function when using CLI commands?
You don't need to set the log level if you want to disable app.logger logs. Let's check:
app = Flask('')
# app logs are disabled. uncomment to see app logs.
# app.logger.setLevel(logging.INFO)
app.logger.info('Project startup')
So you can configure log level using additional argument:
def create_app(config_class=Config, log_level=None):
app = Flask(__name__)
app.config.from_object(config_class)
if log_level:
app.logger.setLevel(logging.INFO)
One more good way is use 2 different configs(first - for web app, second - for CLI app). In this case you'll have possibility to customize any setting(including log level).
Related
I am trying to use SQLAlchemy not in a view function (I was doing something like this with Flask-APSheduler).
I know that there were already a lot of topics related to this theme, but none of them were helpful to me.
So, first of all I will show my code:
./run.py
from app import create_app
from flask_config import DevConfig, ProdConfig
app = create_app(DevConfig)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
./app/__init__.py
from flask import Flask
from .node import node
from .models import db
def create_app(app_config=None):
app = Flask(__name__, instance_relative_config=False)
app.config.from_object(app_config)
db.init_app(app)
app.register_blueprint(node)
return app
./app/models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Users(BaseFuncs, db.Model):
...
./app/node.py
from flask import Blueprint, request
from .bot import bot, secret
import telebot
node = Blueprint('node', __name__)
#node.route('/{}'.format(secret), methods=['POST'])
def handler():
bot.process_new_updates([telebot.types.Update.de_json(request.get_data().decode('utf-8'))])
return 'ok', 200
./app/bot.py
from flask import current_app as app
...
#bot.message_handler(commands=['test'])
def cmd_test(message):
with app.app_context():
print(Users.query.filter_by(id=0).first())
So when I am trying to call cmd_test from my application I am getting this error:
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.
I tried to use g variable and before_request methods, because every time before calling the database there is a call to the route 'handler', but this also doesn't work.
I also tried to use db.get_app(), but there was no effect.
So my question is how to call database right outside the views?
I have created a small Flask application which stores its data in an sqlite database that I access via flask-sqlalchemy.
However, when I run it, I get the following error:
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.
I have debugged my application and now know that this error stems from these two functions:
def user_exists(email):
if User.query.filter_by(email = email).count() == 0:
return False
else:
return True
def get_user(email):
user = User.query.filter_by(email = email).first()
return user
Now I am wondering: Is it impossible to access the database via flask-sqlalchemy outside of view functions?
For further context, I added the files in which I configure my flask app:
presentio.py
from app import create_app
app = create_app(os.getenv("FLASK_CONFIG", "default"))
app/init.py
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
from config import config
mail = Mail()
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
mail.init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix = "/auth")
from .text import text as text_blueprint
app.register_blueprint(text_blueprint, url_prefix = "/text")
return app
You need to give the flask app a context after you create it.
This is done automatically in view functions, but outside those, you need to do this after you create the app:
app.app_context().push()
See the docs: https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/
app_instance.py
from app import FlaskApp
app = None
def init_instance(env):
global app
app = FlaskApp(env)
def get_instance():
assert app is not None
return app
FlaskApp class is pretty much like this
class FlaskApp(object):
def __init__(self, env):
self.oauth_manager = .... bla bla ..
self.clients_manager = .. bla bla ..
app = Flask(__name__)
app.config.from_object(env)
app = app_wrapper.wrap(app, app.config['NUM_PROXY_SERVERS'])
self.app = app
self.api = Api(self.app, prefix='/v3', default_mediatype='application/json')
self.define_routes()
# Initialize the DB
self.db = Database(self.app)
fmt = "%(asctime)s - %(request_id)s - %(name)s - %(levelname)s - %(message)s"
logging.basicConfig(format=fmt, level=self.app.config.get('LOG_LEVEL'))
request_id.init(app, prefix='MY_API_', internal=False)
def run_server(self):
self.app.run(host=self.app.config['HOST'], port=self.app.config['PORT'], debug=self.app.config['DEBUG'])
def define_routes(self):
# Configure Api Resources
self.api.add_resource(VersionListController, '/my/route', endpoint='versions')
more routes here
self.api.init_app(self.app)
in my app controller
def is_valid_oauth_token(request):
from mobile_module import app_instance
app = app_instance.get_instance()
# more code here
I'm running the app on localhost and getting
assert app is not None
AssertionError
How can "fix" this code? should I be importing from mobile_module import app_instance in every route access? suggestions please
I should state that this app works in production well behind a Nginx
I guess my question is more about python (how to make this work) and less in flask.
The problem is not related to get_instance or init_instance(create_app etc.).
Flask has different states. App will work in out of request context when you initialize app instance(FlaskApp(env)).
As I see in your example, you try to get a application in context of request(def is_valid_oauth_token(request)). It means that is not initialization of application. This is processing while a request is active. This is other state of application - app was created and work in context of some request. In this case you can get application instance using from flask import current_app.
To better understanding how it works/use I recommend to read about flask._app_ctx_stack, app_context() and flask.g.
Hope this helps.
I think the best way to devellop a flask app simple is to follow the official documentation about simple flask project structure here
you need to organize your floder like this :
/yourapplication
/yourapplication
__init__.py
/static
style.css
/templates
layout.html
index.html
login.html
...
and then create your application in init.py file like as follow:
from flask import Flask
def create_app():
"""this method will initialise the flask Ap instance """
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
return app
in your yourapplication directory add the run.py to run the app with the following code :
from yourapplication import create_app
app = create_app()
if __name__ == '__main__':
app.run()
and if you want to use your controller you can do this:
from yourapplication import create_app
def is_valid_oauth_token(request):
app = create_app()
# more code here
this is called application factory design-pattern.
And in addition if you want to put it in production you will need to use WSGI configuration find more here
I am getting confused with configurations and imports once I started using the Flask factory application pattern.
I am creating an application with the function create_app in #app/init.py
I have a config file for setting the development/testing/production variables, and an instance folder with another config file.
def create_app(config_name):
app=Flask(__name__, instance_relative_config=True)
app.config.from_object(app_config[config_name])
app.config.from_pyfile('config.py')
etc...
return app
I am using blueprints and have an authentication view in #app/auth/views.py
I am trying to set up email confirmation tokens using URLSafeTimedSerializer...
from itsdangerous import URLSafeTimedSerializer
#auth.route('/register', methods=['GET','POST'])
def register():
ts = URLSafeTimedSerializer(app.config['SECRET_KEY'])
token = ts.dumps(self.email, salt='email-confirm-key')
etc...
Now my problem is, my variable 'ts' needs the app.config['SECRET_KEY'] set. But I am unable to define the app variable (as is shown in all online tutorials). I get an error when I try to import...(in #app/auth/views.py)
from .. import app
and when I try to import like...
from .. import create_app
Can someone shine light on how to initialize modules using 'app' and app.config outside the flask app factory create_app?
Hope you understand my question.
In this scenario you should use Flask.current_app
from flask import current_app
...
ts = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
From the documentation:
flask.current_app
Points to the application handling the request. This
is useful for extensions that want to support multiple applications
running side by side. This is powered by the application context and
not by the request context, so you can change the value of this proxy
by using the app_context() method.
This link aso explains further details about the Flask application factory methodology, in particular using current_app to access the app configuration.
I am using the app factory pattern to set up my Flask application. My app uses the Flask-Babel extension, and that is set up in the factory as well. However, I want to access the extension in a blueprint in order to use it,
The factory is in __init__.py.
def create_app(object_name):
app = Flask(__name__)
app.config.from_object(object_name)
babel = Babel(app)
app.register_blueprint(main_blueprint)
app.register_blueprint(category_blueprint)
app.register_blueprint(item_blueprint)
db.init_app(app)
return app
I want to add the following to main.py:
#babel.localeselector
def get_locale():
if 'locale' in session:
return session['locale']
return request.accept_languages.best_match(LANGUAGES.keys())
#application.route('/locale/<locale>/', methods=['GET'])
def set_locale(locale):
session['locale'] = locale
redirect_to = request.args.get('redirect_to', '/')
return redirect(redirect_to) # Change this to previous url
Unfortunately, main.py doesn't have access to the babel variable from the application factory. How should I go about solving this?
Flask extensions are designed to be instantiated without an app instance for exactly this case. Outside the factory, define your extensions. Inside the factory, call init_app to associate the app with the extension.
babel = Babel()
def create_app():
...
babel.init_app(app)
...
Now the babel name is importable at any time, not just after the app has been created.
You already appear to be doing this correctly with the db (Flask-SQLAlchemy) extension.
In the case of your specific babel.localeselector example, it might make more sense to put that next to babel since it's being defined there.