when I run the Flask Server with flask run, I get error 404 in the Index Page.
* Serving Flask app "sf.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [18/Feb/2021 10:25:56] "GET / HTTP/1.1" 404 -
Not Found
The requested URL was not found on the server. If you entered the URL
manually please check your spelling and try again.
Project Structure
.
├── app
│ ├── models.py
│ ├── routes.py
│ └── __init__.py
├── clients
│ └── client.py
├── migrations
├── tests
│ ├── conftest.py
│ ├── test_models.py
│ ├── test_client.py
│ └── __init__.py
├── publisher.py
├── manage.py
├── run_client.py
├── requirements.txt
└── sf.py
/sf.py
from app import create_app
create_app()
/app/__init__.py
from flask import Flask
from . models import db
POSTGRES = {
'user': 'sf',
'pw': 'sf',
'db': 'sf',
'host': 'localhost',
'port': '5432',
}
def create_app():
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
return app
from app import routes
/app/routes.py
from app import create_app
from app.models import Area, Sensor, Monitoring
from flask import request, jsonify
from flask.views import MethodView
app = create_app()
#app.route('/')
def hello_world():
return 'Hello, World!'
...
I need to use the create_app() because I need an that the /clients/client.py use the app.
/clients/client.py
from paho.mqtt.client import Client
import json
from app import create_app
from app.models import db
from app.models import Monitoring
app = create_app()
class CustomClient(Client):
def add_reading(self, reading):
with app.app_context():
db.session.add(reading)
db.session.commit()
def on_connect(self, client, userdata, flags, rc):
print(
"Connected:",
str(client._host) + ":" + str(client._port)
)
def on_subscribe(self, mqttc, obj, mid, granted_qos):
print(
"Subscribed:",
str(mid), str(granted_qos)
)
def on_message(self, client, userdata, message):
msg = message.payload.decode()
print(message.topic, msg)
data = json.loads(msg)
reading = Monitoring(**data)
self.add_reading(reading)
def run(self):
self.connect("localhost", 1883, 60)
self.subscribe("Main/#", 0)
self.loop_forever()
But in this way I get the 404 error. And I'm not sure that I'm using the app properly. It would be fine to have an app and a db session separate, to test models and client without care the app configuration (probably I need to create a separate config for test?). What I've missed?
You are creating three instances of the Flask() object. One is created in sf.py, the others in routes.py and client.py. The first one is used to serve the site, and so doesn't have your route, because the route is registered with the instance created in routes.py. The 3rd instance, in client.py is independent and isn't further altered, so is not an issue here; more on that below.
Don't create multiple copies, at least not and alter the registrations on one and expect those to be available on the other. Instead, use blueprints to register your views, and then register the blueprint with the Flask() object in your create_app() function. That way you can decouple registration of your routes from creating the Flask() object, and still get your routes registered centrally.
In your routes.py, use:
from app.models import Area, Sensor, Monitoring
from flask import Blueprint, request, jsonify
from flask.views import MethodView
bp = Blueprint('main', __name__)
#bp.route('/')
def hello_world():
return 'Hello, World!'
# ...
and then import that blueprint in create_app():
def create_app():
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s:%(pw)s#%(host)s:%(port)s/%(db)s' % POSTGRES
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
from . import routes
app.register_blueprint(routes.bp)
return app
The reason you want to do the import in create_app() is that in most Flask applications you'll also be using one or more Flask extensions that are generally created outside of create_app() so your views can import them. You'd get a circular import if you tried to import one of those objects in your routes module if your routes module was imported into app.py at the top level.
With this change (to using a blueprint), you avoid creating a separate Flask() instance with registrations that the main instance, used for serving your site, won't see. Even your client.py process will be able to access those routes now, should there be a need (e.g. if you need to generate URLs with url_for()).
Here is an example from an in-production Flask project I built for a client recently, the app.py module contains, in part, the following code:
from flask import Flask
from flask_babel import Babel
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate
from flask_security import Security, SQLAlchemyUserDatastore
from flask_sqlalchemy import SQLAlchemy
babel = Babel()
db = SQLAlchemy()
ma = Marshmallow()
migrate = Migrate()
security = Security()
_app_init_hooks = []
app_init_hook = _app_init_hooks.append
def create_app():
app = Flask(__name__)
for f in _app_init_hooks:
f(app)
return app
#app_init_hook
def _configure(app):
"""Load Flask configurations"""
app.config.from_object(f"{__package__}.config")
# optional local overrides
app.config.from_pyfile("settings.cfg", silent=True)
app.config.from_envvar("PROJECT_NAME_SETTINGS", silent=True)
#app_init_hook
def _init_extensions(app):
"""Initialise Flask extensions"""
if app.env != "production":
# Only load and enable when in debug mode
from flask_debugtoolbar import DebugToolbarExtension
DebugToolbarExtension(app)
# Python-level i18n
babel.init_app(app)
# Database management (models, migrations, users)
from .models import Role, User
db.init_app(app)
migrate.init_app(app, db)
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security.init_app(app, user_datastore)
# Marshmallow integration (must run after db.init_app())
ma.init_app(app)
#app_init_hook
def _setup_blueprints(app):
"""Import and initialise blueprints"""
from . import users
from .sections import BLUEPRINTS
for blueprint in (*BLUEPRINTS, users.bp):
app.register_blueprint(blueprint)
return app
I've broken up the various components into separate functions to ease readability and maintainability, there are separate blueprints used for distinct site functions (which drives some automation in the UI).
At the top of the module are several Flask extensions that various routes and other modules need access to without having to worry about circular imports, so the blueprints are imported separately inside of the _setup_blueprints() hook function that is called from create_app().
Your use of create_app() in client.py should be fine because it doesn't add any new configuration to the Flask() instance that you'd want to have access to elsewhere, and presumably client.py is used outside of the Flask webserver process. But I would, personally, just make the result of create_app()an instance attribute of your Client instance. You don't need a global there, you only need it to access the database session easily for when add_reading() is called:
class CustomClient(Client):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs):
# Create a Flask context so we can access the SQLAlchemy session
self._app = create_app()
def add_reading(self, reading):
with self._app.app_context():
db.session.add(reading)
db.session.commit()
# ...
If add_reading() is called very frequently, you could consider making app an instance attribute of CustomClient():
I am learning flask. I have a directory structure that looks something like this.
project
- controllers
-- auth.py
-- main.py
- db
-- setup.py
- models
-- models.py
- templates
-- base.html
-- index.html
-- login.html
-- signup.html
-- 404.html
-__init__.py
The file init.py looks like this
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = '9OLWxND4o83j4K4iuopO'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:#localhost/mission_to_mars'
db.init_app(app)
# blueprint for auth routes in our app
from .controllers.auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non-auth parts of app
from .controllers.main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
I'm trying to import the db variable and create_app() function in controllers/auth.py, controllers/main.py, models/models.py, db/setup.py
I have tried the below syntaxes
from .. import db, create_app
which gives the error:
ImportError: attempted relative import with no known parent package
I have also tried
from project import db, create_app
which gives the error
ModuleNotFoundError: No module named 'project'
I want to know how I can import classes from different directories so that I can use them further in the project.
Thanks in advance
I structured my app like the following using blueprints. The view files are
extremely huge so I divided them into multiple files.
myapp/
__init__.py
admin/
__init__.py
views1.py
views2.py
views3.py
views4.py
static/
templates/
models/
models.py
myapp/init.py
from flask import Flask
from myapp.admin import admin_bp
app = Flask(__name__)
app.register_blueprint(admin_bp)
myapp/admin/__init__.py
from flask import Blueprint, g
from flask_login import current_user
admin_bp = Blueprint('admin', __name__, template_folder='templates')
#admin_bp.before_request
def load_logged_in_user():
if current_user and not current_user.is_anonymous:
user_name = current_user.user_name
g.user = Account.get(user_name)
from . import views1, views2, views3, views4
myapp/admin/view1.py
from . import admin_bp
#admin_bp.route('/hello', methods=['GET'])
def hello():
return 'Hello'
This is working without any specific errors. But those view files and admin/__init__.py file are importing each other (circular dependency), which should be avoided. How to structure my app using blueprints without circular dependency?
I think it is better to use separate blueprints for each view.
Otherwise to avoid circular dependencies you can use add_url_rule() method. So you will have the following files:
myapp/admin/__init__.py
from flask import Blueprint, g, session, abort, request
from flask_login import current_user
admin_bp = Blueprint('admin', __name__, template_folder='templates')
#admin_bp.before_request
def load_logged_in_user():
if current_user and not current_user.is_anonymous:
user_name = current_user.user_name
g.user = Account.get(user_name)
from . import views1, views2
bp.add_url_rule('/hello', view_func=views1.hello)
bp.add_url_rule('/hello2', view_func=views2.hello2)
myapp/admin/view1.py
def hello():
return 'Hello'
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.
How are routes suppose to be handled in flask when using an app factory? Given a package blog that contains everything needed for the app and a management script that creates the app then how are you suppose to reference the app in the routes?
├── blog
├── manage.py
└── blog
├── __init__.py
├── config.py
└── routes.py
manage.py
#!/usr/bin/env python
from flask.ext.script import Manager
manager = Manager(create_app)
# <manager commands>
# ...
# ...
manager.add_option('-c', '--config', dest='config', required=False)
manager.run()
blog/__init__.py
from flask import flask
from .config import Default
def create_app(config=None):
app = Flask(__name__)
app.config.from_object(Default)
if config is not None:
app.config.from_pyfile(config)
return app
blog/routes.py
#app.route() # <-- erm, this won't work now!?
def index():
return "Hello"
The problem is the app is created outside the package so how are the routes suppose to be handled with a setup like this?
Usually I use application factories with blueprint.
blog/__init__.py
from flask import flask
from .config import Default
def create_app(config=None):
app = Flask(__name__)
if config is not None:
app.config.from_pyfile(config)
else:
app.config.from_object(Default)
from blog.routes import route_blueprint
app.register_blueprint(route_blueprint)
return app
blog/routes.py
from flask import Blueprint
route_blueprint = Blueprint('route_blueprint', __name__)
#route_blueprint.route()
def index():
return "Hello"
docs: Application Factories