Prettify project structure with Blueprints

We started already with project structure optimization - DB models are stored in separate folder and files. Templates also looks good. But route handlers (controllers) are still in app.py file. It is bad practice, let's fix it. Flask offers us nice solution - Blueprints (https://flask.palletsprojects.com/en/1.0.x/blueprints/)

Let's move our home and test hello controllers to ./controllers/default.py folder.

default.py
import os
import json
from flask import Blueprint, render_template
from models import User

default = Blueprint('default', __name__)


@default.route('/hello')
def hello_world():
    return 'Hello, World!'


@default.route('/')
def home():

    users = User.query.all()
    print('Users: ', users)

    is_development_mode = os.environ.get('FLASK_ENV', 'production') == 'development'
    if is_development_mode:
        return render_template('home.html', is_development_mode=is_development_mode)
    else:
        with open('./backend/static/app/index.json') as json_file:
            resources = json.load(json_file)
        return render_template('home.html', is_development_mode=is_development_mode, resources=resources)

app.py
import os
from flask import Flask
from flask_migrate import Migrate
from flask_cors import CORS


app = Flask(__name__)
CORS(app)

app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
from models import db, User  # NOQA
db.init_app(app)
migrate = Migrate(app, db, directory="backend/migrations")

from controllers.default import default as default_blueprint  # NOQA
app.register_blueprint(default_blueprint)


if __name__ == "__main__":
    context = ('./key/server.crt', './key/server.key')
    app.run(ssl_context=context, host='0.0.0.0', debug=True)

Now controllers can be organized easily.

UPD (08.05.2020): Also let's update our app entry script with new init flow suggested by Flask documentation - wrap init logic to create_app method (https://flask.palletsprojects.com/en/1.1.x/patterns/appfactories/)

app.py
import os
import datetime
from flask import Flask
from flask_migrate import Migrate
from flask_cors import CORS
# from flask_wtf.csrf import CSRFProtect
from flask.json import JSONEncoder
from sqlalchemy.ext.declarative import DeclarativeMeta


class CustomJSONEncoder(JSONEncoder):

    def default(self, o):
        if isinstance(o.__class__, DeclarativeMeta):
            return o.to_dict()
        if isinstance(o, datetime.datetime):
            return str(o)
        if isinstance(o, datetime.date):
            return str(o)
        return super(CustomJSONEncoder, self).default(o)


def create_app():
    app = Flask(__name__)

    app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
    app.config['SQLALCHEMY_ECHO'] = bool(os.environ.get('SQLALCHEMY_ECHO', False))

    CORS(app)
    # CSRFProtect(app)

    from models import db, User  # NOQA
    db.app = app
    db.init_app(app)

    Migrate(app, db, directory="backend/migrations")

    app.json_encoder = CustomJSONEncoder

    from controllers.auth import login_manager  # NOQA
    login_manager.init_app(app)

    # Controllers
    from controllers.default import default as default_blueprint  # NOQA
    app.register_blueprint(default_blueprint)

    from controllers.auth import auth as auth_blueprint  # NOQA
    app.register_blueprint(auth_blueprint)

    from controllers.test import test_bp as test_blueprint  # NOQA
    app.register_blueprint(test_blueprint)

    from controllers.task import task_bp as task_blueprint  # NOQA
    app.register_blueprint(task_blueprint)

    # Scripts
    from scripts.auth import auth_scripts  # NOQA
    app.register_blueprint(auth_scripts)

    from scripts.task import task_scripts  # NOQA
    app.register_blueprint(task_scripts)

    return app


The only thing still remain in project preparation before we can move forward with main project business logic - authorization. As we plan to publish our app to Heroku we need to close it from other world. In most cases Basic Auth is enough for quick prototype. But let's move deeper and implement regular Users based authentication system.





Comments

Popular posts from this blog

HTTPS in local environment for Angular + Flask project.

Salesforce Authentication 2 (Token Validation and Refresh)

User authentification with Flask-Login