已經開發了幾個flask項目, 是時候總結一下了, 這里涉及到項目源碼的組織和源碼示例.
=========================
目錄結構
=========================
考慮到項目的擴展性, 采用 blueprint 進行組織. 假設 flaskapp 為根目錄, 主要的程序放在 app 包中, 除了后台代碼, 在app目錄下還有templates/static/子目錄. 為了重用, 最好的形式是一個建立 boilerplate 項目.
主要參考文檔為:
https://github.com/mitsuhiko/flask/wiki/Large-app-how-to
http://www.realpython.com/blog/python/python-web-applications-with-flask-part-ii-app-creation
http://www.realpython.com/blog/python/rethink-flask-a-simple-todo-list-powered-by-flask-and-rethinkdb/
flaskapp
├── app
│ ├── __init__.py
│ ├── constants.py
│ ├── users[sub_app/module]
│ │ ├── constants.py
│ │ ├── decorators.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ └── views.py
│ ├── tickets[sub_app/module]
│ │ ├── constants.py
│ │ ├── decorators.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ └── views.py
│ ├── templates
│ │ ├── forms
│ │ │ └── macros.html
│ │ ├── base.html
│ │ ├── index.html
│ │ ├── base_another.html
│ │ ├── 500.html (server error page)
│ │ ├── 404.html (not found page)
│ │ ├── method_not_allowed.html
│ │ ├── access_forbidden.html
│ │ ├── users
│ │ │ ├── profile.html
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ └── tickets
│ │ ├── create.html
│ │ └── close.html
│ └── static
│ ├── favicon.ico
│ ├── img
│ ├── js
│ │ ├── main.js #our own js code
│ │ └── vendor
│ │ ├── bootstrap.min.js
│ │ └── jquery-1.7.2.min.js
│ └── css
│ ├── layout.less
│ ├── reset.less
│ └── vendor
│ └── bootstrap.css
├── flaskapp.db
├── config.py
├── requirements.txt
├── runserver.py
├── shell.py
├── tests 目錄
└── docs 目錄
----------------------
項目級的單元
----------------------
runserver.py 用來啟動 web server, 從app包中進入flask app對象, 然后直接啟動.
config.py 存儲一些db的 connection 配置, 以及Flask SECRET_KEY 等等. 更多的配置項見 http://flask.pocoo.org/docs/config/
----------------------
應用級別的單元
----------------------
flaskapp/app/__init__.py, 作為整個app的入口, 做如下工作.
1.加載flask的config,
2.[如使用Flask-SQLAlchemy插件]創建 SqlAlchemy 的db 實例.
3.[如沒使用Flask-SQLAlchemy插件]定義3個函數, 分別加上@app.before_request和@app.teardown_request和@app.after_request. before_request和teardown_request函數非常適合做創建和關閉db connection工作. after_request函數不適合用來關閉db connection, 因為after_request函數在有unhandled exception發生的情況下, 會被跳過. 而teardown 函數總是能保證被調用的.
4.注冊sub app blueprint, 比如users和tickets
5.設置root url 和favicon.ico 的路由,
6.創建login_manager, 比如使用flask-login插件來創建一個login_manager
----------------------
子應用級別的單元,
----------------------
=========================
目錄結構
=========================
考慮到項目的擴展性, 采用 blueprint 進行組織. 假設 flaskapp 為根目錄, 主要的程序放在 app 包中, 除了后台代碼, 在app目錄下還有templates/static/子目錄. 為了重用, 最好的形式是一個建立 boilerplate 項目.
主要參考文檔為:
https://github.com/mitsuhiko/flask/wiki/Large-app-how-to
http://www.realpython.com/blog/python/python-web-applications-with-flask-part-ii-app-creation
http://www.realpython.com/blog/python/rethink-flask-a-simple-todo-list-powered-by-flask-and-rethinkdb/
flaskapp
├── app
│ ├── __init__.py
│ ├── constants.py
│ ├── users[sub_app/module]
│ │ ├── constants.py
│ │ ├── decorators.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ └── views.py
│ ├── tickets[sub_app/module]
│ │ ├── constants.py
│ │ ├── decorators.py
│ │ ├── forms.py
│ │ ├── models.py
│ │ └── views.py
│ ├── templates
│ │ ├── forms
│ │ │ └── macros.html
│ │ ├── base.html
│ │ ├── index.html
│ │ ├── base_another.html
│ │ ├── 500.html (server error page)
│ │ ├── 404.html (not found page)
│ │ ├── method_not_allowed.html
│ │ ├── access_forbidden.html
│ │ ├── users
│ │ │ ├── profile.html
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ └── tickets
│ │ ├── create.html
│ │ └── close.html
│ └── static
│ ├── favicon.ico
│ ├── img
│ ├── js
│ │ ├── main.js #our own js code
│ │ └── vendor
│ │ ├── bootstrap.min.js
│ │ └── jquery-1.7.2.min.js
│ └── css
│ ├── layout.less
│ ├── reset.less
│ └── vendor
│ └── bootstrap.css
├── flaskapp.db
├── config.py
├── requirements.txt
├── runserver.py
├── shell.py
├── tests 目錄
└── docs 目錄
----------------------
項目級的單元
----------------------
runserver.py 用來啟動 web server, 從app包中進入flask app對象, 然后直接啟動.
config.py 存儲一些db的 connection 配置, 以及Flask SECRET_KEY 等等. 更多的配置項見 http://flask.pocoo.org/docs/config/
----------------------
應用級別的單元
----------------------
flaskapp/app/__init__.py, 作為整個app的入口, 做如下工作.
1.加載flask的config,
2.[如使用Flask-SQLAlchemy插件]創建 SqlAlchemy 的db 實例.
3.[如沒使用Flask-SQLAlchemy插件]定義3個函數, 分別加上@app.before_request和@app.teardown_request和@app.after_request. before_request和teardown_request函數非常適合做創建和關閉db connection工作. after_request函數不適合用來關閉db connection, 因為after_request函數在有unhandled exception發生的情況下, 會被跳過. 而teardown 函數總是能保證被調用的.
4.注冊sub app blueprint, 比如users和tickets
5.設置root url 和favicon.ico 的路由,
6.創建login_manager, 比如使用flask-login插件來創建一個login_manager
----------------------
子應用級別的單元,
----------------------
稱為subapp或稱為module, 目錄采用
復數形式
flaskapp/app/users/models.py, 和User相關的表模型
flaskapp/app/users/constants.py, 和User module相關的constant, 比如用戶的激活狀態, 用戶的類型.
flaskapp/app/users/forms.py, 集中所有User module相關的表單類, 比如class LoginForm(Form) 和 class RegisterForm(Form) 類.
flaskapp/app/users/decorators.py, 和User module相關的一些decorator, 比如 requires_login, 供 views.py 使用.
flaskapp/app/users/views.py, 充當url路由角色(Flask是基於MVT模型, 這里的view相當於MVC模型中的Controller). 依據web請求類型和請求的url, 路由到指定的view函數, 在view函數中, 做邏輯處理, 然后, 或展現form, 或跳轉到其他url.
----------------------
templates目錄
----------------------
flaskapp/app/templates/base.html, 模板的模板, 根據需要, 可以設置多個base頁面
flaskapp/app/templates/forms/macros.html, 定義一些宏, 供form頁面調用, 用來渲染form的元素
flaskapp/app/templates/users/login.html, 在flaskapp/app/users/views.py應該有一個同名的view函數
----------------------
static目錄
----------------------
flaskapp/app/static/favicon.ico, 16 × 16 pixels and in the ICO format
=========================
源碼示例
=========================
------------------------------
runserver.py
------------------------------
runserver.py 用來啟動 web server.
------------------------------
config.py
------------------------------
config.py 存儲一些db的 connection 配置, 以及Flask SECRET_KEY 等等. 更多的配置項見 http://flask.pocoo.org/docs/config/
------------------------------
app/__init__.py
------------------------------
flaskapp/app/__init__.py, 作為整個app的入口, 做如下工作.
1.加載flask的config,
2.[如使用Flask-SQLAlchemy插件]創建 SqlAlchemy 的db 實例.
3.[如沒使用Flask-SQLAlchemy插件]定義3個函數, 分別加上@app.before_request和@app.teardown_request和@app.after_request. before_request和teardown_request函數非常適合做創建和關閉db connection工作. after_request函數不適合用來關閉db connection, 因為after_request函數在有unhandled exception發生的情況下, 會被跳過. 而teardown 函數總是能保證被調用的.
4.注冊sub app blueprint, 比如users和tickets
5.設置root url 和favicon.ico 的路由,
6.創建login_manager, 比如使用flask-login插件來創建一個login_manager
------------------------------
app/users/views.py.py
------------------------------
用法:
{% from "macros.html" import form_field %}
macros.html內容, 可以自動將form兼容 bootstrap. 內容摘自 https://gist.github.com/rawrgulmuffins/6025599
flaskapp/app/users/models.py, 和User相關的表模型
flaskapp/app/users/constants.py, 和User module相關的constant, 比如用戶的激活狀態, 用戶的類型.
flaskapp/app/users/forms.py, 集中所有User module相關的表單類, 比如class LoginForm(Form) 和 class RegisterForm(Form) 類.
flaskapp/app/users/decorators.py, 和User module相關的一些decorator, 比如 requires_login, 供 views.py 使用.
flaskapp/app/users/views.py, 充當url路由角色(Flask是基於MVT模型, 這里的view相當於MVC模型中的Controller). 依據web請求類型和請求的url, 路由到指定的view函數, 在view函數中, 做邏輯處理, 然后, 或展現form, 或跳轉到其他url.
----------------------
templates目錄
----------------------
flaskapp/app/templates/base.html, 模板的模板, 根據需要, 可以設置多個base頁面
flaskapp/app/templates/forms/macros.html, 定義一些宏, 供form頁面調用, 用來渲染form的元素
flaskapp/app/templates/users/login.html, 在flaskapp/app/users/views.py應該有一個同名的view函數
----------------------
static目錄
----------------------
flaskapp/app/static/favicon.ico, 16 × 16 pixels and in the ICO format
=========================
源碼示例
=========================
------------------------------
runserver.py
------------------------------
runserver.py 用來啟動 web server.
# -*- coding: utf-8 -*- from __future__ import absolute_import from app import app app.run()
------------------------------
config.py
------------------------------
config.py 存儲一些db的 connection 配置, 以及Flask SECRET_KEY 等等. 更多的配置項見 http://flask.pocoo.org/docs/config/
# -*- coding: utf-8 -*- from __future__ import absolute_import import os from datetime import timedelta _basedir = os.path.abspath(os.path.dirname(__file__)) DEBUG = True SECRET_KEY = os.urandom(24) PERMANENT_SESSION_LIFETIME=timedelta(seconds=24*60*60) CSRF_ENABLED = True CSRF_SESSION_KEY = SECRET_KEY
------------------------------
app/__init__.py
------------------------------
flaskapp/app/__init__.py, 作為整個app的入口, 做如下工作.
1.加載flask的config,
2.[如使用Flask-SQLAlchemy插件]創建 SqlAlchemy 的db 實例.
3.[如沒使用Flask-SQLAlchemy插件]定義3個函數, 分別加上@app.before_request和@app.teardown_request和@app.after_request. before_request和teardown_request函數非常適合做創建和關閉db connection工作. after_request函數不適合用來關閉db connection, 因為after_request函數在有unhandled exception發生的情況下, 會被跳過. 而teardown 函數總是能保證被調用的.
4.注冊sub app blueprint, 比如users和tickets
5.設置root url 和favicon.ico 的路由,
6.創建login_manager, 比如使用flask-login插件來創建一個login_manager
# -*- coding: utf-8 -*- from __future__ import absolute_import from flask import Flask, g, render_template, send_from_directory import os import os.path _basedir = os.path.abspath(os.path.dirname(__file__)) configPy=os.path.join(os.path.join( _basedir,os.path.pardir), 'config.py') app = Flask(__name__) # create our application object app.config.from_pyfile(configPy) #app.debug=True #change some attribute after load configuration flask_sqlalchemy_used=True # 如果使用Flask-SQLAlchemy了 db = SQLAlchemy(app) #create a db (SQLAlchemy) object from our app object login_manager = LoginManager(app) #create a LoginManager Object from our app object #add our view as the login view to finish configuring the LoginManager login_manager.login_view = "users.login_view" #register the users module blueprint from app.users.views import mod as usersModule app.register_blueprint(usersModule) #register the tickets module blueprint from app.tickets.views import mod as ticketsModule app.register_blueprint(ticketsModule) def connect_db(): # 如果沒使用Flask-SQLAlchemy if not flask_sqlalchemy_used: return sqlite3.connect('/path/to/database.db') else: return None @app.before_request def before_request(): """Make sure we are connected to the database each request.""" if not flask_sqlalchemy_used: g.db = connect_db() @app.teardown_request def teardown_request(response): """Closes the database again at the end of the request.""" if not flask_sqlalchemy_used: g.db.close() return response #***************** # controllers #***************** @app.route('/favicon.ico') def favicon(): return send_from_directory(os.path.join(app.root_path, 'static'), 'ico/favicon.ico') @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 @app.route("/") def index(): return render_template('index.html')
------------------------------
app/users/views.py.py
------------------------------
# -*- coding: utf-8 -*- from __future__ import absolute_import from flask import Blueprint, render_template, flash, redirect, session, url_for, request, g from flask.ext.login import login_user, logout_user, login_required from app import app, db, login_manager from forms import LoginForm, RegistrationForm from app.users.models import User mod = Blueprint('users', __name__) #register the users blueprint module @login_manager.user_loader def load_user(user_id): return User.query.get(user_id) @mod.route('/login/', methods=('GET', 'POST')) def login_view(): form = LoginForm(request.form) if form.validate_on_submit(): user = form.get_user() login_user(user) flash("Logged in successfully.") return redirect(request.args.get("next") or url_for("index")) return render_template('users/login.html', form=form) @mod.route('/register/', methods=('GET', 'POST')) def register_view(): form = RegistrationForm(request.form) if form.validate_on_submit(): user = User() form.populate_obj(user) db.session.add(user) #使用SqlAlchemy保存 db.session.commit() login_user(user) return redirect(url_for('index')) return render_template('users/register.html', form=form) @login_required @mod.route('/logout/') def logout_view(): logout_user() return redirect(url_for('index'))
macros.html, 是個jinja2的宏文件, 我們在該文件中可定義一些宏, 供form頁面調用, 用來渲染form的元素. 用法是, 在我們的html文件中, 引入這個宏文件即可.
用法:
{% from "macros.html" import form_field %}
macros.html內容, 可以自動將form兼容 bootstrap. 內容摘自 https://gist.github.com/rawrgulmuffins/6025599
{% macro form_field(field) -%} {% set with_label = kwargs.pop('with_label', False) %} {% set placeholder = '' %} {% if not with_label %} {% set placeholder = field.label.text %} {% endif %} <div class="control-group {% if field.errors %}error{% endif %}"> {% if with_label %} <label for="{{ field.id }}" class="control-label"> {{ field.label.text }}{% if field.flags.required %} *{% endif %}: </label> {% endif %} <div class="controls"> {% set class_ = kwargs.pop('class_', '') %} {% if field.flags.required %} {% set class_ = class_ + ' required' %} {% endif %} {% if field.type == 'BooleanField' %} <label class="checkbox"> {{ field(class_=class_, **kwargs) }} {{ field.label.text|safe }} </label> {% else %} {% if field.type in ('TextField', 'TextAreaField', 'PasswordField') %} {% set class_ = class_ + ' input-xlarge' %} {% elif field.type == 'FileField' %} {% set class_ = class_ + ' input-file' %} {% endif %} {% if field.type == 'SelectField' %} {{ field(class_=class_, **kwargs) }} {% else %} {{ field(class_=class_, placeholder=placeholder, **kwargs) }} {% endif %} {% endif %} {% if field.errors %} <span class="error help-inline">{{ field.errors|join(', ') }}</span> {% endif %} {% if field.description %} <p class="help-block">{{ field.description|safe }}</p> {% endif %} </div> </div> {%- endmacro %}