六.Tutorial
1.项目结构(Project Layout)
当我们创建好项目后,本文默认采用Pycharm创建,根据项目需求应该提前规划好项目结构,除了自动生成的static和tamplates文件夹还有app.py文件外,还要规划好各个模块。
2.应用配置(Application Setup)
对于Flask实例化后对象,通常需要在全局调用对象的一些配置函数,为了更方便管理,需要创建一个工厂函数来统一管理,而这个函数的路径为项目目录下的__init__.py文件,具体目录可以参考下面的一个博客项目目录
图1 在项目包下的__init__.py文件中创建工厂函数create_app()
这时候就可以在app.py文件中导入这个工厂函数,并调用函数返回一个加载了若干配置后的app对象,然后就可以像之前一样通过app.run()来运行(图中的manager之后会用到,此处可以忽略掉)
图2 在启动文件app.py中加载配置好的app对象
官方文档字在这里还是采用了先配置环境变量后再运行启动,为了更加方便运行,可以也效仿上面这种将app对象的配置项都放到一起的思想,将系统配置项也都放到一起。在项目根目录下创建一个settings.py文件,然后可以将常用的配置创建成为一个Config类,然后在工厂函数中通过app.config.from_object(settings.Config)来调用配置文件
图3 在根目录下创建全局的配置文件settings.py
3.定义和访问数据库(Define and Access the Database)
官方文档在这里使用的是SQLite数据库,然后在python文件中去操作sql语句从而实现对数据的操作,与普通python链接数据库不同的是,此处要在Flask的app对象中去初始化该功能,不过目前flask对于数据库操作主要使用的是SQLalchemy,后面会详细介绍到。
4.蓝图和视图
视图函数是为响应应用程序请求而编写的代码。Flask使用路由来将传入的请求URL匹配到应该处理它的视图。该视图返回数据再转换为响应传出。Flask也可以根据它的名字和参数生成一个URL到一个视图。
蓝图的作用就是更清晰的划分路由,如果一个项目有多个模块,那么对于不同模块来说,万一都有同名的路由,比如博客项目中,用户模块中有/user这个路由,而文章模块中也有这个/user路由,在装饰器中都写成了@app.route('/user')那么就分不清是属于谁的路由了,蓝图的出现就是为了给路由划分为清晰的模块,比如用户的路由就是@user.route('/user')而文章的路由就是@article.route('/user'),换个角度来思考的话就是说不能把所有模块的视图函数都放在一个view.py文件中,那么将非常臃肿难以维护,所以也有必要按模块划分视图函数,这时候也要用到蓝图。
蓝图的划分也比较简单,第一步就是创建蓝图对象
from flask import Blueprint
article_bp = Blueprint('article', __name__)
@article_bp.route('/publish', methods=['POST', 'GET'])
def publish_article():
return "Succese"
第二部就是在工厂函数中注册蓝图对象
from apps.user.views import user_bp1
def create_app():
...
app.register_blueprint(user_bp1)
return app
然后就可以使用蓝图对象来加载路由了
5.模板
当启动应用访问到对应的路由时,这时候只会返回视图函数中的返回值,如果想看到html界面的话,需要使用render_templates()函数来跳转到响应的html界面,html文件放在根目录下的templates文件夹中。Flask是通过Jinja来渲染模板的,Jinja的安全机制也保护了模板中的数据安全,Jinja的语法和python有些类似,主要是通过变量{{ a }}和语句{{% if %}}来在模板中控制,注释使用{{# #}}。
base.html
<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
<h1>Flaskr</h1>
<ul>
{% if g.user %}
<li><span>{{ g.user['username'] }}</span>
<li><a href="{{ url_for('auth.logout') }}">Log Out</a>
{% else %}
<li><a href="{{ url_for('auth.register') }}">Register</a>
<li><a href="{{ url_for('auth.login') }}">Log In</a>
{% endif %} </ul> </nav>
<section class="content">
<header> {% block header %}{% endblock %} </header>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %} {% block content %}{% endblock %}
</section>
模板是可以继承的,如果上面的是基础模板,那么里面的block就是一个一个的坑,具体填的内容可以由字模板去继承然后重写,字模板继承要使用{%extend 'base.html'%}
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="username">Username</label>
<input name="username" id="username" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Register">
</form>
{% endblock %}
6.静态文件
静态文件中可以添加css、js或者images文件,比如css样式,可以通过link标签加载到html模板中,使用方法是:
{{ url_for('static', filename='style.css') }}
7.部署相关问题
部署操作会单独下面的文章介绍