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.
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'm writing a Flask app and I instantiate a mongo database in main.py.
I've got a submodule called user.py that holds class User. main.py takes login credentials and sends it to the class User which handles the rest.
How can I cleanly pass my mongo instance to the User class? I've tried static variables in a config.py file but they don't work because the variables are always None when user.py tries to use them.
Right now I'm resorting to passing in mongo as a parameter, but this seems like a dirty way to do it considering there will be many modules. Here's my code;
# Setup app and database
app = Flask(__name__)
app.config['MONGO_URI'] = 'mongodb://'
mongo = PyMongo(app)
You can import mongo directly into your user.py module.
To avoid circular import error, you just have to move the imports to the bottom of the file. As long as you import User into main after app is defined, it should resolve the circular import:
user.py
from .main import mongo
# class User():
# ... Your Code
main.py
from flask import Flask
from flask_pymongo import PyMongo
app = Flask(__name__)
mongo = PyMongo(app)
from .user import User
Moving imports to the bottom are normally not a good idea, but in Flask is quite common. Below is an example of a similar scenario from the official flask documentation:
# app.py
from flask import Flask
app = Flask(__name__)
import app.views
# views.py
from app import app
#app.route('/')
def index():
return 'Hello World!'
http://flask-.readthedocs.io/en/0.6/patterns/packages/#simple-packages
Do the importing at the bottom of the file [...]
Every Python programmer hates them, and yet we just added some: circular imports (That’s when two modules depend on each other. In this case views.py depends on init.py). Be advised that this is a bad idea in general but here it is actually fine. The reason for this is that we are not actually using the views in init.py and just ensuring the module is imported and we are doing that at the bottom of the file.
I have two application factory functions - one creates the "customer" app, and the other creates the "admin" backend app. Both of the factory functions essentially do what is described here - create a flask app and register some extensions to it and then add some blueprints(with a url_prefix). I glue the two apps together via the create_combined_app() from below. It is the return value of that function which I register with my Flask-Script's Manager.
def create_combined_app(config_name):
customer_app = create_customer_app(config_name)
admin_app = create_admin_app(config_name)
from werkzeug.wsgi import DispatcherMiddleware
customer_app.wsgi_app = DispatcherMiddleware(customer_app.wsgi_app, {
'/admin': admin_app
})
return customer_app
And then this is how I run it.
def make_me_an_app():
return create_combined_app(config)
manager = Manager(make_me_an_app)
...
if __name__ == '__main__':
manager.run()
I want to do some testing which involves getting all GET routes of my app and making sure they load. I followed the example from here, but I only see the urls of the customer app, and none of the urls from the admin backend.
#main.route("/site-map")
def site_map():
from flask import current_app, jsonify
links = []
app = current_app
for rule in app.url_map.iter_rules():
if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
return jsonify(links)
The admin backend works when I try to access it from the browser - it all works nicely, except that I don't see the admin's urls when I call /site-map.
Thanks! :)
I think DispatcherMiddleware create separate apps. Which mean you created customer_app and admin_app. Those 2 live as standalone. They don't know each others, therefor current_app is just the show customer_app.
Here is the describe from Flask http://flask.pocoo.org/docs/0.12/patterns/appdispatch/
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.
I have a Python Flask app that accesses the Github API. For this I need to store an access token. What is the common practice to store that data and how do I access that inside my app?
from flask import Flask, request
app = Flask(__name__)
app.config['DEBUG'] = True
#app.route('/',methods=['POST'])
def foo():
...
Flask has a custom context to store app variables:
http://flask.pocoo.org/docs/1.0/appcontext/
You can use g object to store your variables:
from flask import g
g.github_token = 'secret'
And after initialization:
from flask import g
token = g.github_token
The simpliest way is to place it into configuration module (regular python .py file) and then import and use it in your code as suggested by this snippet on Flask site.