I am using Flask foundation to begin with my new flask app.
The init.py file has a method:
def create_app(object_name, env="prod"):
"""
An flask application factory, as explained here:
http://flask.pocoo.org/docs/patterns/appfactories/
Arguments:
object_name: the python path of the config object,
e.g. sservice.settings.ProdConfig
env: The name of the current environment, e.g. prod or dev
"""
app = Flask(__name__)
app.config.from_object(object_name)
app.config['ENV'] = env
#init the cache
cache.init_app(app)
debug_toolbar.init_app(app)
#init SQLAlchemy
db.init_app(app)
login_manager.init_app(app)
# Import and register the different asset bundles
assets_env.init_app(app)
assets_loader = PythonAssetsLoader(assets)
for name, bundle in assets_loader.load_bundles().iteritems():
assets_env.register(name, bundle)
# register our blueprints
from controllers.main import main
app.register_blueprint(main)
return app
that is imported in manage.py.
But what If I need to use this app variable to access the application configuration in modules within the application? I can't use current_app outside request contexts. Creating one is ugly.
I need to have a app variable in my models.py file:
In models.py
# how to import? Below doesn't work
from appname import app
# access config
print(app.config)
I can't call this method create_app, because it should be only called once to create the application. Not anytime you need to import the app. How should I solve this?
I only want to use create_app() exactly once outside the package to give it the wsgi server, but I don't want to use it within the package.
What is working now for me:
Wherever there is no current_app (outside of request contexts I guess) just use something like this
app = Flask(__name__)
app.config.from_object('appname.settings_file.DevConfig')
print(app.config)
Related
I have an extremely large application that is factored into many blueprints. I need to configure the entire application to save files into a directory when a user uploads files. So I am setting ["SESSION_FILE_DIR"] = 'C:/some/path' to the path where files would live after upload in the app.py file.
The documentation reads that configuration settings are shared across the blueprints. I'm experiencing one issue that is not working and below is a stripped down example to replicate my problem to support my question. So, to debug I've created an extremely simple version just printing the path to screen to see what is happening.
If I head over to the URL .../print_dir then the ["SESSION_FILE_DIR"] = 'C:/some/path' is printed to screen. However, if I head over to the URL defined within the blueprint .../new then I am given an error of NameError: name 'server' is not defined.
How can I configure my app such that the same ["SESSION_FILE_DIR"] can be used across blueprints?
The contents of my main app.py are as follows:
from flask import Flask, render_template, request, session
from flask_session import Session
import tempfile
server = Flask(__name__)
server.config["SESSION_PERMANENT"] = False
server.config["SESSION_TYPE"] = "filesystem"
server.config["SESSION_FILE_DIR"] = 'C:/some/path'
server.secret_key = 'abcdefg'
### Import and Register Blueprints
from tools.routes import my_bp
server.register_blueprint(my_bp)
#server.route('/')
def homepage():
return "Hello"
#server.route('/print_dir')
def homepage2():
return server.config["SESSION_FILE_DIR"]
if __name__ == '__main__':
server.run(debug=True)
and now suppose the blueprint lives in a subdirectory called tools and contains the following:
from flask import Flask, render_template, request, session, Blueprint
from flask_session import Session
my_bp = Blueprint("my_bp", __name__)
#my_bp.route('/new', methods=['POST', 'GET'])
def path():
path = server.config["SESSION_FILE_DIR"]
return path
To access the app.config from within a Blueprint, you can import current_app from flask.
Example:
# ./app.py
from flask import Flask
from views.blueprint import bp
app = Flask(__name__)
# Set the config you want:
app.config['IMPORTANT_DIRECTORY'] = '~/path/to/important/directory'
# Register your blueprint
app.register_blueprint(bp)
# ./views/blueprint.py
from flask import Blueprint, current_app
bp = Blueprint('bp', __name__)
#bp.route('/path')
def get_path():
# access the config
path = current_app.config['IMPORTANT_DIRECTORY']
return path
You can find more info in the api docs for flask.
I'm a bit confused by the changes to Flask 1.0.
The docs suggest creating a factory for the application in __init__.py where app=create_app(config_file) which is called from run.py.
Now in prior versions of Flask I had could from application import app in say a blueprint controller because app was not returned from create_app(). I can't call create_app() again, yet I don't have access to #app.route, app.config etc, etc.
I've tried and had little success pushing the context. Now there are various not-so-nice ways of doing this but what is the "canonical" way?
The concept of an application factory is not new to Flask 1.0. You don't have to use a factory if your app doesn't need one.
If you do use an app factory, then you usually do not register any routes directly on the app. You'd create a blueprint instead, register your routes to the blueprint, and in the app factory, attach the blueprint to the app.
Anywhere you need to access the app configuration, you'd use the current_app proxy.
For example, in the views.py module in your application you could create a blueprint just for the views; I included an example use of current_app to access configuration:
from flask import Blueprint, current_app
bp = BluePrint('main', __name__)
#bp.route(...)
def some_route_name(...):
# ...
if current_app.config['SOME_CONFIGURATION_SETTING']:
# ...
and you'd register the blueprint with
def create_app(config_filename=None):
app = Flask(__name__)
# configuration setup, use the confuration module as a default
from . import configuration
app.config.from_object(config)
app.config.from_envvar("PROJECTNAME_SETTINGS", silent=True)
if config_filename is not None:
app.config.from_pyfile(config_filename)
from . import views
app.register_blueprint(views.bp)
# other registrations
return app
I am taking over a Flask application that has a user module, but does not have a landing page. The structure of the project is:
|-application.py
|-manage.py
|-settings.py
|-/templates
|----base.html
|----index.html
|----navbar.html
|----/user
|--------views.py
application.py:
from flask import Flask
....
def create_app(**config_overrides):
app = Flask(__name__)
app.config.from_pyfile('settings.py')
app.config.update(config_overrides)
db.init_app(app)
from user.views import user_app
app.register_blueprint(user_app)
return app
user/views.py:
from flask import Blueprint, render_template, request, redirect, session, url_for, abort
...
user_app = Blueprint('user_app', __name__)
#user_app.route('login', methods = ('GET','POST'))
def login():
....
I placed index.html in the templates folder.
Should I place a view.py in the root directory where I would put a route to an index.html?
You can add additional routes anywhere you want.
However, since the package uses a create_app() app factory, you can't register those routes with an #app.route() decorator; the app is not created in a way you can just import.
So yes, creating a views.py module is a good organisational idea, but do create a Blueprint() there too, and register that blueprint in the create_app() function with the Flask() app instance.
In views.py:
from flask import Blueprint
bp = Blueprint('main', __name__)
#main.route('/')
def index():
# produce a landing page
and in create_app() in application.py, add
import views
app.register_blueprint(views.bp)
(I use a convention of using the bp variable name for all my blueprints, and then just importing the module and registering the module.bp attribute).
It's the explicit import and app.register_blueprint() call that ties any of the blueprints used in a Flask project into the final app's routes. Blueprints can share the same prefix, including having no prefix.
One thing to note: here the views module is now a top-level module next to application.py. It'd be better if everything was moved into a package, giving you more freedom over what names you use. All modules in a single package are namespaced, kept separate from other top-level modules such as json and time and flask, so there won't be clashes when you want to use the same name for one of the additional modules in your project.
You'd move everything but manage.py into a subdirectory, with a project-appropriate name, and move application.py to __init__.py. Imports can then use from . import ... to import from the current package, etc.
I use factory pattern and flask extensions such as flask-admin during the development of web application. I want to load some configurations in flask-admin when the app haven't created. So i use the current_app.config["SOME_CONFIG"] to get the config value.But i got the Working outside of application context. exception. The code as follows:
# __init__.py
from flask import Flask
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_name)
app.config.from_pyfile("config.py")
from admin import admin
admin.init_app(app)
return app
# admin/__init__.py
from flask import current_app
from flask_admin import Admin
admin = Admin(name=current_app.config["ADMIN_NAME"], template="bootstrap2")
Your application is still in the setup state during the create_app function (see http://flask.pocoo.org/docs/0.11/appcontext/). During the setup state you need to have a reference to the application object to access it, you can't use current_app.
You could instantiate the Admin object within the create_app function using:
admin = Admin(name=app.config["ADMIN_NAME"], template="bootstrap2")
OR
change the admin variable and create a function in your admin/__init__.py:
admin = object()
def instantiate_admin(config):
global admin
admin = Admin(name=config["ADMIN_NAME"], template="bootstrap2")
return admin
and use this in create_app():
from admin import instantiate_admin
admin = instantiate_admin(app.config)
admin.init_app(app)
All you need to do is set it up like the following.
# config.py
class Config(object):
ADMIN_NAME = 'admin'
# __init__.py
from flask import Flask
from flask_admin import Admin
# initiate all extensions here
admin = Admin(template='bootstrap2')
def create_app(config):
app = Flask(__name__)
app.config.from_object(config)
admin.init_app(app)
return app
# wsgi.py
from . import create_app
from config import Config
app = create_app(Config)
if __name__ == '__main__':
app.run()
And in you admin package
# admin/__init__.py
from .. import admin # import extensions from __init__.py
admin.add_view('blah')
Below is a link to an real world example. I scrubbed info so it is more generic but this is how i setup all my flask apps.
http://hastebin.com/likupoxoxi.py
As long as you are running the dev server you shouldn't have issues that keeps it in the context of the application.
I have an application that is constructed as follows:
app = Flask(__name__)
app.wsgi_app = DispatcherMiddleware(frontend.create_app(), {
'/api': api.create_app()
})
app.config['DATABASE'] = db
I want to access the same database in both the frontend and api apps, but when I run something like current_app.config['DATABASE'] in Blueprints registered to api, that raises KeyError: 'DATABASE'. Is it possible to inherit configurations so that tests, etc. need only modify the top-level abstraction? Thanks.
Simply change your create_app methods on frontend and api to take a configuration dictionary and use flask.Config to create a configuration with all the properties of app.config (loadable from environmental variables, etc.):
from flask import Config
from werkzeug.wsgi import DispatcherMiddlware
config = Config()
config.from_envvar("YOUR_PROGRAM_CONFIG")
app = DispatcherMiddlware(frontend.create_app(config), {
'/api': api.create_app(config)
})
Then you can merge the provided config with each of your app's configurations:
def create_app(config):
app = Flask(__name__)
app.config.update(config)
# Potentially, load another config
app.config.from_envvar("YOUR_PROGRAM_CONFIG_FRONTEND", silent=True)
return app
Note that there is no need to create an app to route to other apps - the dispatcher middleware can already do that for you.
Also note that if you are already using blueprints it may make more sense to simply ship the blueprints and compose them on a single application, rather than using dispatcher middleware (depending, of course on how complex your apps are).