loading...
Cover image for How I Structure My Flask Apps

How I Structure My Flask Apps

aligoren profile image Ali GOREN ・3 min read

This post previously published on my blog


Hi. I have been developing Flask applications as a side project for 5 years. After all these years, I found the right structure I need for me.

First Steps

Firstly, I'm always using virtualenv to isolate my projects. For example, we want to develop a poll app.

mkdir poll_app

cd poll_app

virtualenv .

source bin/activate

Python Libraries I Always Use

I'm developing applications that require a database. So, I always use flask_script and flask_migrate libraries. I don't like Flask's CLI tool.

I create a python file called manage.py such as Django's in the root folder. For example;

from MYAPP.data.models import db
from MYAPP import app
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

db.init_app(app)
migrate = Migrate(app, db)
manager = Manager(app)

manager.add_command('db', MigrateCommand)


if __name__ == "__main__":
    manager.run()

I'm using like that;

python manage.py db init # --> init migrations

python manage.py db migrate # --> migrate models

python manage.py db upgrade # --> apply changes

python manage.py db --help # --> :)

Main app file

I create a file app.py in the root folder when I create a new project and then it changes like that.

from MYAPP import app

# To do: This place will change later
config = {
    "development": "config.Development"
}

if __name__ == "__main__":
    app.config.from_object(config["development"])
    app.run()

Config File

I also create a file called config.py in the root folder.


class BaseConfig(object):
    """ Base config class. This fields will use by production and development server """

    ORIGINS = ["*"] # for api calls
    SECRET_KEY = 'YOUR SECRET KEY'


class Development(BaseConfig):
    """ Development config. We use Debug mode """

    PORT = 5000
    DEBUG = True
    TESTING = False
    ENV = 'dev'


# Currently we only have development config.
# If you have production, you will need to pass it to here.
config = {
    'development': 'config.Development'
}


def configure_app(app):
    """ 
        App configuration will be here. 

        Parameters
        ----------

        app : Flask
            app instance
    """

    app.config.from_object(config['development'])

Folder Structure

I create a folder in the root directory. Let's say folder name is om_core. I create two folders in the om_core.

Their name api and data. The api folder stores application logic and routes. For example, I created a folder called user.

This folder contains two files called init.py and controllers.py file. Our other api layers will be like that. The controller file should be like that;

from flask import Blueprint, jsonify, request

from MYAPP.data.models import db, User

user = Blueprint('user', __name__)

@user.route('/', methods=['GET'])
def get_users():

    return jsonify({ "message": "Hi user :)"})

@user.route('/<int:id>', methods=['GET'])
def users(id):

    return jsonify({ "id": id })

I always use blueprints.

The data folder stores models. For example, I created a file called models.py

from flask_sqlalchemy import SQLAlchemy
from MYAPP import app

# We didn't pass app instance here.
db = SQLAlchemy()

class User(db.Model):
    """ Model for user management """

    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(100))
    surname = db.Column(db.String(100))
    active = db.Column(db.Boolean(), default=True)
    created_at = db.Column(db.DateTime, default=db.func.now())
    updated_at = db.Column(db.DateTime, default=db.func.now())

    def __init__(self, email, password, name, surname, active, created_at, updated_at):
        self.email = email
        self.password = password
        self.name = name
        self.surname = surname
        self.active = active
        self.created_at = created_at
        self.updated_at = updated_at

Let's get back to the om_core folder. I create a file called init.py to use API layers as endpoints.

from flask import Flask
from flask_cors import CORS


from config import BaseConfig
from config import configure_app

app = Flask(__name__)

from MYAPP.api.user.controllers import user

""" Corst settings will be here. We maybe use this endpoint later. """
cors = CORS(app, resources={
    r'/api/*': {
        'origins': BaseConfig.ORIGINS
    }
})

configure_app(app)

app.url_map.strict_slashes = False


app.register_blueprint(user, url_prefix='/api/users')

You don't need to use Flask-CORS if you don't want to allow request from different origins. I'm using it to allow requests from different origins.

Screenshot for My Project Structure

This is a screenshot for my project structure.

That's all. If you want to see this project on the GitHub: https://github.com/foss-dev/open-monitoring

Thanks for reading.

Discussion

pic
Editor guide
Collapse
dbanty profile image
Dylan Anthony

Thanks for the post! I have a few questions if you don’t mind:

  1. Any reason you choose to create and import the app directly instead of using the factory method?

  2. How do you usually run Flask apps in production? (e.g. gunicorn, waitress, etc.)

  3. How do you manage configs for different environments?

  4. How do you distribute the services to the server?

Collapse
aligoren profile image
Ali GOREN Author

Hi. Thanks for your questions :)

1-) Actually, this is a habit for me. I never used a factory method in my Flask apps. Also, I don't know what are the benefits of factory methods.

2-) I use gunicorn.

3-) I usually use dotenv. But I used class-based configs for this post :)

4-) I don't understand this question :/

Thanks :)

Collapse
adekoder profile image
adekoder

Benefit of using factory methods

Testing. You can have instances of the application with different settings to test every case.

Multiple instances. Imagine you want to run different versions of the same application. Of course you could have multiple instances with different configs set up in your webserver, but if you use factories, you can have multiple instances of the same application running in the same application process which can be handy.

Thread Thread
aligoren profile image
Ali GOREN Author

Hmm, can you show an example about factory methods for the newbies :)

Thread Thread
adekoder profile image
adekoder

Sure in a bit

Thread Thread
aligoren profile image
Ali GOREN Author

Thanks, I'll be waiting for your contribution. Thanks.

Collapse
costular profile image
Diego Francisco Concepción

The fourth question means:
How do you deploy your monolith/microservices to your server?

Thread Thread
aligoren profile image
Ali GOREN Author

Hmm. I'm using the EB CLI.

Firstly, I install it.

pip install awsebcli — upgrade

I also set secret keys for the elastic bean in the ~/.aws/config file.

[profile eb-cli]
aws_access_key_id = MY_KEY
aws_secret_access_key = MY_SECRET

and then I use these commands.

eb init -p python-3.6 my-flask-app — region WHICH_REGION_DO_YOU_USE

eb init

eb create flask-env

eb open

Did you mean this? :P I hope :/)

Thread Thread
dbanty profile image
Dylan Anthony

Yes, thank you. I’ve never used elastic beanstalk before, I’ll add it to the list of services to explore. Thanks for all your answers!

Thread Thread
aligoren profile image
Ali GOREN Author

Actually, I only used it twice times. I'll use gcloud or azure next times. (This is my plan). Thanks :)

Collapse
jayso_o1 profile image
Sowah Joseph Anyetei

I think the question four was referring to whether it's a microservice or monolithic app.

Collapse
cybermischa profile image
Mischa Spiegelmock

I run flask on AWS lambda. This is my application structure: github.com/jetbridge/sls-flask/

Collapse
jldohmann profile image
Jesse

Started using Flask recently, and this article is really helpful, thank you! Also enjoying the discussions in the comments.

Collapse
avelino profile image
Avelino

I like Flask Blueprint architecture flask.pocoo.org/docs/1.0/blueprints/

Collapse
aligoren profile image
Ali GOREN Author

Yes, I use blueprints :)

Collapse
perymerdeka profile image
perymerdeka

ask how to call app.config['some conf'] in views?

Collapse
ayushnita profile image
Ayushnita

I also trying to create a command-line project that creates this code automatically.
github.com/openuniquesolution/flas...

If you feel its good idea pls start raising pr