This is the code read but Flask not rendering html
from flask import Flask,render_template
import psycopg2
import psycopg2.extras
app=Flask(__name__)
app.route('/')
def index():
return render_template('index.html')
if __name__=="__main__":
app.run(debug=True, port=9001)
If I'm not mistaking, it's just a typo error. Supposed you already have a file called index.html in your templates folder. So your tree look like this:
.
└── my_app/
├── templates/
│ └── index.html
└── run.py
This code should work:
from flask import Flask, render_template
app=Flask(__name__)
#app.route('/') # <-- You are missing the '#' here
def index():
return render_template('index.html')
if __name__ == "__main__": # <-- Note this too
app.run(debug=True, port=9001)
Now you can access to your project at http://127.0.0.1:9001/
To learn more about Flask view decorator, go here.
For more information about what mean if __name__ == "__main__":, you can read more here.
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 following the book Mastering flask's recommended file structure.
(The name of my project is Paw)
In Paw/paw/__init__.py:
def create_app(object_name):
app = Flask(__name__)
app.config.from_object(object_name)
db.init_app(app)
robot = LoggingWeRobot(token='banana', enable_session=True)
robot.init_app(app, endpoint='werobot', rule='/wechat')
attach_debugging_logger(app)
app.register_blueprint(poll_blueprint)
app.register_blueprint(wechat_blueprint)
return app
Note that the robot variable is actually needed in my blueprint, wechat, found in: Paw/paw/controllers/wechat.py
#robot.handler
def request_logging_middleware(message, session):
app.logger.debug("\n%s", request.data)
return False # This allows other handlers to continue execution
So my problem is that my blueprint has no access to the robot variable. However, the robot variable should be created in create_app in Paw/paw/__init__.py because I am trying to follow the application factory pattern.
Any recommendation on how to fix this? My project can be found here and I am trying to follow this application structure
Simply use the same pattern you are using for db - create robot elsewhere and import it into your Paw/paw/__init__.py file, just as you do with db:
import db from models
import robot from wechat_setup
# wechat_setup is where you would invoke
# robot = LoggingWeRobot(token='banana', enable_session=True)
def create_app(object_name):
app = Flask(__name__)
app.config.from_object(object_name)
db.init_app(app)
robot.init_app(app, endpoint='werobot', rule='/wechat')
I usually put project global variables in one file (say gvars.py).
Then the project structure will be some sort like this:
.
├── etc
│ └── webapp.py
├── models
│ └── common.py
├── views
│ └── common.py
├── gvars.py
└── webapp.py
In other files we just do this:
from gvars import db, robot # or other variables
I'm trying to write tests for a simple Flask application. Structure of the project is following:
app/
static/
templates/
forms.py
models.py
views.py
migrations/
config.py
manage.py
tests.py
tests.py
import unittest
from app import create_app, db
from flask import current_app
from flask.ext.testing import TestCase
class AppTestCase(TestCase):
def create_app(self):
return create_app('test_config')
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
def test_hello(self):
response = self.client.get('/')
self.assert_200(response)
app/init.py
# app/__init__.py
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
db.init_app(app)
return app
app = create_app('default')
from . import views
When I launch the tests, test_hello fails because response.status_code is 404. Tell me, please, how can I fix it? It seems, that app instance doesn't know anything about view functions in the views.py. If it needs the whole code, it can be found here
Your views.py file mount the routes in the app created in your __init__.py file.
You must bind these routes to your created app in create_app test method.
I suggest you to invert the dependency. Instead the views.py import your code, you can make a init_app to be imported and called from your __init__.py or from the test file.
# views.py
def init_app(app):
app.add_url_rule('/', 'index', index)
# repeat to each route
You can do better than that, using a Blueprint.
def init_app(app):
app.register_blueprint(blueprint)
This way, your test file can just import this init_app and bind the blueprint to the test 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