Confused by Flask's behaviour - python

I started by creating my Flask app the old school way: I had a Python package where I defined a variable called app, initialised it and then imported my code:
# -*- coding: utf-8 -*-
import os
from flask import Flask
app = Flask(__name__)
app.config.from_object('config')
app.secret_key = os.urandom(12)
from dashboard import forms, models, views
While adding unit tests to my project I found that I should use app factories so I created a factory:
# -*- coding: utf-8 -*-
import os
def create_app()
from flask import Flask
app = Flask(__name__)
app.config.from_object('config')
app.secret_key = os.urandom(12)
app = create_app()
from dashboard import forms, models, views
Except that with the factory my views are not loaded. Any route I call returns a 404. Without the factory everything works fine.
How can I diagnose what's going on?

Your create_app have to return app variable:
def create_app()
from flask import Flask
app = Flask(__name__)
app.config.from_object('config')
app.secret_key = os.urandom(12)
return app
Because default return is None

Related

Integrate multiple Dash apps into Flask

I`m trying to integrate multiple Dash apps into a Flask application, but not able to do so.
I was able to integrate one Dash app into Flask, using the following structure:
dashboard1.py
def create_dashboard(server):
dash_app = dash.Dash(server=server,
routes_pathname_prefix='/dash1/',
external_stylesheets=[dbc.themes.BOOTSTRAP],
)
....
return dash_app.server
init.py
from flask import Flask
from flask_assets import Environment
def create_app():
"""Construct core Flask application with embedded Dash app."""
f_app = Flask(__name__, instance_relative_config=False)
f_app.config.from_object('config.Config')
assets = Environment()
assets.init_app(f_app)
with f_app.app_context():
# Import parts of our core Flask app
from . import routes
from .assets import compile_static_assets
# Import Dash application
from .plotlydash.dashboard import create_dashboard
app = create_dashboard(f_app)
# Compile static assets
compile_static_assets(assets)
return app
routes.py
from flask import render_template, redirect
from flask import current_app as app
#app.route('/dash1')
def dash1():
return render_template('dash1.html', app_data=app_data)
app.py
from application import create_app
app= create_app()
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
Everything is working fine with the first Dash app. I want to create another menu/tab in the application and integrate a second dash app. How could I do this? I have tried the following but it has not resulted successful. Only the link of the first app works.
dashboard2.py
def create_dashboard2(server):
dash_app = dash.Dash(server=server,
routes_pathname_prefix='/dash2/',
external_stylesheets=[dbc.themes.BOOTSTRAP],
)
....
return dash_app.server
init.py
from flask import Flask
from flask_assets import Environment
def create_app():
"""Construct core Flask application with embedded Dash app."""
f_app = Flask(__name__, instance_relative_config=False)
f_app.config.from_object('config.Config')
assets = Environment()
assets.init_app(f_app)
with f_app.app_context():
# Import parts of our core Flask app
from . import routes
from .assets import compile_static_assets
# Import Dash application
from .plotlydash.dashboard1 import create_dashboard
from .plotlydash.dashboard2 import create_dashboard2
app = create_dashboard(f_app)
app2 = create_dashboard2(f_app)
# Compile static assets
compile_static_assets(assets)
return app, app2
routes.py
from flask import render_template, redirect
from flask import current_app as app
#app.route('/dash1')
def dash1():
return render_template('dash1.html', app_data=app_data)
#app.route('/dash2')
def dash2():
return render_template('dash2.html', app_data=app_data)
app.py
from application import create_app
app, app2= create_app()
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
app2.run(host='0.0.0.0', debug=True)
Could you please help me with some pointer/indications of what I might be doing wrong?
To answer #mLstudent33's question about callbacks initialization in the comments - there is a good blog post about it - https://hackersandslackers.com/plotly-dash-with-flask.
I followed their instructions and this worked for me:
For example, dashboard1.py:
def create_dashboard(server):
dash_app = dash.Dash(
server=server,
routes_pathname_prefix='/dash1/',
external_stylesheets=[dbc.themes.BOOTSTRAP],
)
dash_app.layout = html.Div([
# ... Layout stuff
])
# Initialize callbacks after our app is loaded
# Pass dash_app as a parameter
init_callbacks(dash_app)
return dash_app.server
def init_callbacks(dash_app):
#dash_app.callback(
# Callback input/output
....
)
def update_graph(rows):
# Callback logic
# ...

Getting 404 not found on Flask app deployed on PythonAnywhere

I've rummaged through maybe 50 different answers to this and still I haven't manage to fix it... I'm pretty new to flask and python.
I have an app which was running great locally but I've struggled with deploying on python anywhere. Initially I had a few import modules issues, now it runs but doesn't return any html template, despite not seeing any other issue. The main issue I had was that it couldn't find the "routes" app from wsgi, and I sort of fixed adding the app = Flask(name) line on routes.py (the short blueprint object is not callable).
routes.py:
from flask import Blueprint, render_template, request, redirect, send_file
import pyqrcode
from pyqrcode import QRCode
import subprocess
from extensions import db
from models import Link
app = Flask(__name__)
short = Blueprint('short', __name__, url_prefix='/')
#short.route('/index')
def index():
return render_template('index.html')
init.py
from flask import Flask
from extensions import db
from routes import short
def create_app(config_file='settings.py'):
app = Flask(__name__)
app.config.from_pyfile(config_file)
db.init_app(app)
app.register_blueprint(short)
return app
wsgi.py
import sys
# add your project directory to the sys.path
project_home = u'/home/b297py/mysite'
if project_home not in sys.path:
sys.path = [project_home] + sys.path
# import flask app but need to call it "application" for WSGI to work
from routes import app as application
For the purpose of testing, I've placed all the html templates both in the root directory and in the specific /template directory but it just didn't fix the issue.
In wsgi.py you are not calling create_app so you are never registering the blueprint. You should replace :
from routes import app as application
by something like :
from package_name import create_app
application = create_app()
(Example: https://www.pythonanywhere.com/forums/topic/12889/#id_post_50171)
Also as you mentioned, the fix adding app = Flask(__name__) to routes.pyallows you to bypass create_app (so you should remove it if you want to stick to the create_app approach).

How to use flask-caching in my structure of project

My code structure. I tried but kept getting error cannot import name 'caching'. I guess my method isn't correct as caching will not have app initiation when I import caching in external file.
xyz
-app.py
-run.py
-urls
-v2.py
-resource
-views.py
-external.py
run.py
from app import create_app
if __name__ == "__main__":
career_app = create_app()
career_app.run(host=HOST,
port=PORT,
debug=True)
app.py
from flask import Flask
from flask_caching import Cache
caching = Cache(config={'CACHE_TYPE': 'simple'})
def create_app():
"""Create web app."""
app = Flask(__name__)
configure_app(app)
caching.init_app(app)
setup_blueprints(app)
return app
external.py
from app import caching
v1.py
v2_api.add_resource(UserConfigView, '/user/config',
endpoint='user_config_view')
It is a simple factory app setup
ext.py
from flask_caching import Cache
cache = Cache()
app.py
def create_app():
app = Flask(__name__)
register_extensions(app)
...
def register_extensions(app):
cache.init_app(app, config=settings.params.CACHE_CONFIG)

Import statement flow

My app layout
my_app
__init__.py
my_app
__init__.py
startup
__init__.py
create_app.py
create_users.py
common_settings.py
core
__init__.py
models.py
views.py
errors
__init__.py
errors.py
Inner __init__.py
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__) # The WSGI compliant web application object
db = SQLAlchemy(app) # Setup Flask-SQLAlchemy
manager = Manager(app) # Setup Flask-Script
from my_app.startup.create_app import create_app
create_app()
create_app.py
def create_app(extra_config_settings={}):
# Load all blueprints with their manager commands, models and views
from my_app import core
return app
core/__init__.py
# from . import views
views.py
from my_app import app, db
from flask import Flask, request
#app.errorhandler(Error)
def handle_invalid_usage(error):
response = jsonify(data=error.to_dict())
response.status_code = error.status_code
return response
I based this code on a tutorial I found. Everything works fine as long as I leave the __init__.py in the core folder empty.
When I don't, I get a NameError: name Error is not defined in my views.py. Error comes from errors.py.
I have three questions:
1) Why does this happen only when I leave the import statement in core/__init__.py.
2)
create_app.py
app.config.from_envvar('ENV_SETTINGS_FILE')
# Other app.config commands here
from my_app import core
return app
What happens when from my_app import core runs?
3) Finally when I return app, is this to ensure that Inner __init__.py file contains the updated app object?
Any explanations would be greatly appreciated!
Trying to build and configure an app with dynamic imports is really bad news and confusing for the reasons you are discovering. A much better and understandable pattern would be a more typical factory:
def create_app():
app = Flask(__name__)
configure_app(app, config)
register_db(app)
add_views(app)
add_manager(app)
return app
if __name__ == '__main__':
app = create_app()
app.run()
But since you're asking, your problem is here:
from my_app import app, db
from flask import Flask, request
#app.errorhandler(Error) # Error is not imported
def handle_invalid_usage(error):
response = jsonify(data=error.to_dict())
response.status_code = error.status_code
return response
The error occurs because views.py is imported, the code compiler comes across Error and cannot find a reference to it.
For your second question: from my_app import core causes core.__init.__ to run, which (presumably) adds the views onto the app object.

NameError: name 'app' is not defined with Flask

I have the following structure in my project
\ myapp
\ app
__init__.py
views.py
run.py
And the following code:
run.py
from app import create_app
if __name__ == '__main__':
app = create_app()
app.run(debug=True, host='0.0.0.0', port=5001)
views.py
#app.route("/")
def index():
return "Hello World!"
_init_.py
from flask import Flask
def create_app():
app = Flask(__name__)
from app import views
return app
I'm trying to use the factory design pattern to create my app objects with different config files each time, and with a subdomain dispatcher be able to create and route different objects depending on the subdomain on the user request.
I'm following the Flask documentation where they talk about, all of this:
Application Context
Applitation Factories
Application with Blueprints
Application Dispatching
But I couldn't make it work, it seems that with my actual project structure there are no way to pass throw the app object to my views.py and it throw and NameError
NameError: name 'app' is not defined
After do what Miguel suggest (use the Blueprint) everything works, that's the final code, working:
_init.py_
...
def create_app(cfg=None):
app = Flask(__name__)
from api.views import api
app.register_blueprint(api)
return app
views.py
from flask import current_app, Blueprint, jsonify
api = Blueprint('api', __name__)
#api.route("/")
def index():
# We can use "current_app" to have access to our "app" object
return "Hello World!"

Categories

Resources