改造原因
单个脚本文件
- 优点:编写小型Web应用方便
缺点:
- 伸缩性差,应用复杂后,单个大型源码文件会出现众多问题
- 应用在全局中创建,无法动态修改配置
项目结构
在命令行中执行tree > readme.md 可将目录结构写入readme.md文件blog
├─app
│ ├─templates/
│ ├─static/
│ ├─main/
│ ├─__init__.py
│ ├─views.py
│ ├─forms.py
│ ├─errors.py
│ ├─auth/
│ ├─__init__.py
│ ├─views.py
│ ├─forms.py
│ ├─__init__.py
│ ├─email.py
│ ├─models.py
├─migrations/
├─tests/
├─venv/
├─requirements.txt
├─config.py
├─run.py
配置选项
应用设置配置的方法
app.config对象
app.config[''] == xxx
配置类:需要导入配置模块
class config_object:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
app.config.from_object(config_object)
文件方式
config.py
DEBUG=True
run.py
from flask import Flask
app = Flask(__name__)
# silent=true 文件不存在时不报错。默认为false
app.config.from_pyfile("config.py", silent=True)
配置设置示例
config.py
Config中包含通用配置,各子类定义专用的配置
末尾config字典注册了不同环境的配置,并注册了一个默认配置
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>'
FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
MAIL_SERVER = 'smtp.googlemail.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
app/init.py
from config import config
app.config.from_object(config['development'])
应用包
用来保存程序的所有代码、模板和静态文件。数据库模型和电子邮件支持函数也被移到了这个
包中,分别保存为 app/models.py 和 app/email.py
工厂函数
为解决动态修改配置,延迟创建应用实例,把创建过程移到可显式调用的工厂函数。这样可以给脚本留出配置应用的时间,还可以创建多实例。
工厂函数在app包构建文件中定义
app/init.py
from flask import Flask
from flask_bootstrap import Bootstrap
from flask-mail import Mail
bootstrap = Bootstrap()
mail = Mail()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_name)
bootstrap.init_app(app)
mail.init_app(app)
return app
蓝本blueprint
转换成应用工厂函数后,定义路由变得复杂,现在应用在运行时创建,必须调用create_app()后才能使用app.route装饰器。flask提供蓝本解决该问题,蓝本定义的路由和错误程序处理休眠状态,直到注册到应用中,才成为应用一部分。使用位于全局作用域中的蓝本时,定义路由和错误处理程序的方法几乎与单脚本应用一样
创建蓝本
创建蓝本通过Blueprint类创建,需要传入两个参数,第一个为蓝本名称,第二个为蓝本所在包或者模块,通常使用python变量name即可
app/main/init.py
from flask import Blueprint
from . import view, errors
blueprint = Blueprint("main", __name__)
注册蓝本
app/init.py
def create_app(config_name):
# ...
from .main import blueprint as main_blueprint
app.register(main_blueprint)
return app
视图函数
app/main/errors.py
如果使用errorhandler装饰器,那么只有蓝本中的错误才能触发处理程序。要想注册应用全局的错误处理程序,必须使用app_errorhandler装饰器
from flask import render_template
from . import main
@main.app_errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@main.app_errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
app/main/views.py
在蓝本中编写视图函数主要有两点不同
- 与前面的错误处理程序一样,路由装饰器由蓝本提供,因此使用的是main.route,而非app.route;
- url for()函数的用法不同。url for()函数的第一个参数是路由的端点名,在应用的路由中,默认为视图函数的名称。例如,在单脚本应用中,index()视图函数的URL可使用url for(‘index’)获取。端点名url_for(“main.index”),url for()函数还支持一种简写的端点形式,在蓝本中可以省略蓝本名,例如url for(‘.index’) ```python from flask import render_template, redirct, url_for from . import main from .forms import NameForm
@main.route(‘/‘, methods=[‘GET’, ‘POST’])
def index():
form = NameForm()
if form.validate_on_submit():
return redirect(url_for(‘.index’))
return render_template(‘index.html’,form=form, name=session.get(‘name’))
<a name="LJymk"></a>
# 启动文件
run.py
```python
from app import create_app
app = create_app('default')
文件启动
(venv) $ set flask_app=run.py
(venv) $ flask run
需求文件
程序中必须包含一个 requirements.txt 文件,用于记录所有依赖包及其精确的版本号。在其他电脑重新生成虚拟环境,看根据该文件快速安装依赖包
生成\更新需求文件
(venv) $ pip freeze >requirements.txt
根据需求文件安装模块
(venv) $ pip install -r requirements.txt
安装指定版本及升级
(venv) $ pip install package==version
(venv) $ pip install --upgrade xxx