惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
博客园 - 三生石上(FineUI控件)
S
Securelist
U
Unit 42
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Simon Willison's Weblog
Simon Willison's Weblog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
T
Tenable Blog
The Hacker News
The Hacker News
The Register - Security
The Register - Security
IT之家
IT之家
博客园 - 【当耐特】
Spread Privacy
Spread Privacy
P
Privacy & Cybersecurity Law Blog
博客园_首页
T
Tailwind CSS Blog
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
Know Your Adversary
Know Your Adversary
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
T
Tor Project blog
C
CERT Recently Published Vulnerability Notes
Apple Machine Learning Research
Apple Machine Learning Research
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
A
Arctic Wolf
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
V2EX
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
V
Visual Studio Blog
月光博客
月光博客
爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
G
GRAHAM CLULEY
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Heimdal Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

Just lepture

我用 AI 造新語 丟失的表達欲 註冊郵箱攻擊 個人域名郵箱免費方案 Markdown on ruby markup Display country flags emoji on Windows 週記,垂死病中驚坐起 程序員與文學衝突 Fireside 遷移記 Typlog 三週年 How to style RSS feed 談談獨立播客 貓與網絡暴力 那霸的夜 Authlib Under BSD License PyCon JP 2018 記 摩登 OAuth 2.0:簡介 夜思 Announcement of Authlib 三藩記 佐渡與阿賀町記 週記,九月末 前端的基礎修養:ARIA Live Regions 週記,九月三週
Structure of a Flask Project
2018-04-21 · via Just lepture

Flask itself is very flexible. It has no certain pattern for a project folder structure, which is very good for experienced developers to organize things in their own favors. However, people new to Flask will get confused, they need some guide on it, and usually they are going to find something works but not good (or even bad).

I didn't know such a problem until someone reported an issue to Authlib. And I can't understand the problem either. Then another person explained it to me with a project structure, I finally got it. I was terrified that lots of posts, guide, boilerplates are backward importing modules from project root __init__.py:

# project/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    db.init_app(app)

# project/auth/models.py
from .. import db

class User(db.Model):
    # define columns

The code itself will work, but when your projects grow, sooner or later you will face a cyclic dependencies problem. For instance, another extension requires to init with the User model:

# project/__init__.py
from flask_sqlalchemy import SQLAlchemy
from another_extension import AnotherExtension
from project.auth.models import User

db = SQLAlchemy()
ext = AnotherExtension(User)

Oops, a cyclic dependency occurs. Because auth.models is importing db from the root, root can not import User module. This is a common cyclic problem, not limited to Flask. It is easy to fix, but junior developers may find it very hard. So why not avoid such thing from the very begining? Actually, if you have read the official documentation, in application factories you can find this piece of code:

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)
    from yourapplication.model import db
    db.init_app(app)
    from yourapplication.views.admin import admin
    from yourapplication.views.frontend import frontend
    app.register_blueprint(admin)
    app.register_blueprint(frontend)
    return app

See, we put db in yourapplication.model.

I always keep this one certain rule when writing modules and packages:

Don't backward import from root __init__.py.

That's why I submitted a ticket to Flask as soon as I found this problem. People need a guide on folder structure. And here I'm going to share my suggestions. But think it yourself, don't treat mine as a golden rule.

Functional Based Structure

There are many ways to setup your project folder structure. One is by its function. For instance:

project/
  __init__.py
  models/
    __init__.py
    base.py
    users.py
    posts.py
    ...
  routes/
    __init__.py
    home.py
    account.py
    dashboard.py
    ...
  templates/
    base.html
    post.html
    ...
  services/
    __init__.py
    google.py
    mail.py
    ...

All things are grouped by its function. If it hehaves as a model, put it in models folder; if it behaves as a route, put it in routes folder. Build a create_app factory in project/__init__.py, and init_app of everything:

# project/__init__.py
from flask import Flask

def create_app()
    from . import models, routes, services
    app = Flask(__name__)
    models.init_app(app)
    routes.init_app(app)
    services.init_app(app)
    return app

Here is a trick by me. In official documentation, db of Flask-SQLAlchemy is registered in this way:

from project.models import db
db.init_app(app)

So my trick is define a init_app in every folder's __init__.py, and unify the init progress as one:

# project/models/__init__.py
from .base import db

def init_app(app):
    db.init_app(app)

# project/routes/__init__.py
from .users import user_bp
from .posts import posts_bp
# ...

def init_app(app):
    app.register_blueprint(user_bp)
    app.register_blueprint(posts_bp)    

# ...

App Based Structure

Another famous folder structure is app based structure, which means things are grouped bp application. For instance:

project/
  __init__.py
  db.py
  auth/
    __init__.py
    route.py
    models.py
    templates/
  blog/
    __init__.py
    route.py
    models.py
    templates/
...

Each folder is an application. This pattern is used by default in Django. It doesn't mean this pattern is better, you need to choose a folder structure depending on your project. And sometime, you will have to use a mixed pattern.

It is the same as above, we can init_app as:

# project/__init__.py
from flask import Flask

def create_app()
    from . import db, auth, blog
    app = Flask(__name__)
    db.init_app(app)
    auth.init_app(app)
    blog.init_app(app)
    return app

Configuration

Loading configuration would be another issue that many people find difficult, it is also a folder structure problem. I don't know how other people are doing, I'm just sharing my solution.

  1. Put a settings.py in project folder, treat it as static configuration.
  2. Load configration from environment variable.
  3. Update configration within create_app.

Here is a basic folder structure for configration:

conf/
  dev_config.py
  test_config.py
project/
  __init__.py
  settings.py
app.py

Define a create_app to load settings and environment variable:

# project/__init__.py
import os
from flask import Flask

def create_app(config=None)
    app = Flask(__name__)
    # load default configuration
    app.config.from_object('project.settings')
    # load environment configuration
    if 'FLASK_CONF' in os.environ:
        app.config.from_envvar('FLASK_CONF')
    # load app sepcified configuration
    if config is not None:
        if isinstance(config, dict):
            app.config.update(config)
        elif config.endswith('.py'):
            app.config.from_pyfile(config)
    return app

This FLASK_CONF is a python file path which contains configrations. It can be any name you want, e.g. your project is called Expanse, you can name it as EXPANSE_CONF.

I use this FLASK_CONF to load production configurations.


Again, Flask is very flexible, there is no certain patterns. You can always find your favors. These are just my suggestions, do not blind by anyone.

I don't like to write posts like this. But there are so many wrong guide, I hope this post can get a better SEO, so that bad posts don't mislead people.