改造原因
单个脚本文件
- 优点:编写小型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 = Trueapp.config.from_object(config_object)
文件方式
config.py
DEBUG=True
run.py
from flask import Flaskapp = Flask(__name__)# silent=true 文件不存在时不报错。默认为falseapp.config.from_pyfile("config.py", silent=True)
配置设置示例
config.py
Config中包含通用配置,各子类定义专用的配置
末尾config字典注册了不同环境的配置,并注册了一个默认配置
import osbasedir = 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 = TrueFLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>'FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')@staticmethoddef init_app(app):passclass DevelopmentConfig(Config):DEBUG = TrueMAIL_SERVER = 'smtp.googlemail.com'MAIL_PORT = 587MAIL_USE_TLS = TrueMAIL_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 configapp.config.from_object(config['development'])
应用包
用来保存程序的所有代码、模板和静态文件。数据库模型和电子邮件支持函数也被移到了这个
包中,分别保存为 app/models.py 和 app/email.py
工厂函数
为解决动态修改配置,延迟创建应用实例,把创建过程移到可显式调用的工厂函数。这样可以给脚本留出配置应用的时间,还可以创建多实例。
工厂函数在app包构建文件中定义
app/init.py
from flask import Flaskfrom flask_bootstrap import Bootstrapfrom flask-mail import Mailbootstrap = 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 Blueprintfrom . import view, errorsblueprint = Blueprint("main", __name__)
注册蓝本
app/init.py
def create_app(config_name):# ...from .main import blueprint as main_blueprintapp.register(main_blueprint)return app
视图函数
app/main/errors.py
如果使用errorhandler装饰器,那么只有蓝本中的错误才能触发处理程序。要想注册应用全局的错误处理程序,必须使用app_errorhandler装饰器
from flask import render_templatefrom . 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```pythonfrom app import create_appapp = 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
