本章示例程序是一个非常简单的留言板程序SayHello,涉及的知识完全是前面六个章节的内容 。这一章会基于这个程序介绍一种组织代码的形式,并了解Web程序开发流程,对前面六章的知识进行简单的回顾复习。
在具体的开发中,代码编写主要分为前端页面和后端程序。前端开发的主要流程:
1)根据功能规格书画页面草图
2)根据草图做交互式原型图
3)根据原型图开发前端页面(HTML、CSS、JavaScript)
后端开发的主要流程:
1)数据库建模
2)编写表单类
3)编写视图函数和相关的处理函数
4)在页面中使用Jinja2替换虚拟数据
本章的示例程序SayHello非常简单,就是在表单中输入姓名和留言,按下提交按钮后,就可以将留言加入到页面的消息列表中。
程序主页设计如图:
前几章的示例程序都采用单脚本的形式存储代码,随着项目的增大,把所有代码都放在app.py会导致可读性降低,不方便管理。更好地组织方式是将单一的模块升级为包(Package),把不同的代码分模块存放。
在Python中,每一个有效的Python 文件(.py)都是模块。每一个包含
__init__.py
文件的文件夹都被视作包,包让你可以使用文件夹来组织模块。__init__.py
文件通常被称作构造文件,文件可以为空,也可以用来放置包的初始化代码。当包或包内的模块被导入时,构造文件将被自动执行。
SayHello程序的核心组件都放到一个包中,包的名称通常使用程序名称,除了程序代码,Flask项目还包括其他必要的组件,如下说明
组件 | 说明 |
---|---|
sayhello/__init__.py | 构造文件,包含程序实例 |
sayhello/templates/ | 模板 |
sayhello/static/ | 静态文件,其中又包含js和css文件夹 |
sayhello/views.py | 视图函数 |
sayhello/forms.py | 表单 |
sayhello/errors.py | 错误处理 |
sayhello/models.py | 数据库模型 |
sayhello/commands.py | 自定义flask命令 |
sayhello/settings.py | 配置文件 |
和前面几章不同的是,配置不仅可以通过config对象直接写入,还可以写在单独的文件中,配置文件的内容主要是配置变量 = 值
。
在创建程序实例后,使用config对象的form_pyfile()方法即可加载配置,传入配置模块的文件名作为参数:
...
app = Flask(__name__)
app.config.form_pyfile('settings.py')
创建程序实例
使用包组织程序代码后,创建程序实例、初始化扩展等操作可以在程序包的构造文件(__init__.py)中实现。
# 文件__init__.py
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
app = Flask('sayhello')
app.config.from_pyfile('settings.py')
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
db = SQLAlchemy(app)
bootstrap = Bootstrap(app)
moment = Moment(app)
from sayhello import views, errors, commands
当程序启动时,最先被执行的是包含程序实例的脚本,在本例中也就是构造文件(__init__.py)。
虽然本例中,程序实例化在构造文件中,但注册在实例上的各种处理函数都在其他脚本文件中(例如views.py、errors.py等),为了将处理函数与程序实例关联起来,我们可以在构造文件中导入这些模块,也可以在这些模块中导入构造文件。但是在构造文件中导入这些模块会在构造文件执行时,将构造函数和错误处理函数一并注册到程序中,保障程序可以正常执行,因此我们选用在构造文件中导入这些模块,如代码中最后一行。
后端程序开发
1、数据库建模
在程序设计阶段就确定了需要使用哪些表来存储数据,表中存储哪些字段以及各个表的关系。因此我们首先进行数据库建模。
在本例中用于保存留言的Message模型如代码所示:
# 文件models.py
from datetime import datetime
from sayhello import db
class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
body = db.Column(db.String(200))
timestamp = db.Column(db.DateTime, default=datetime.now, index=True)
2、创建表单类
留言表单由表单类HelloForm表示,表单中使用了文本区域字段TextAreaField。
#文件forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Length
class HelloForm(FlaskForm):
name = StringField('Name', validators=[DataRequired(), Length(1, 20)])
body = TextAreaField('Message', validators=[DataRequired(), Length(1, 200)])
submit = SubmitField()
3、编写视图函数
视图函数主要存在两个文件中,一个是正常逻辑的处理views.py,另一个是错误处理errors.py。
正常逻辑的处理:
1)处理GET请求,从数据库中查询所有的消息记录,返回渲染后的包含消息列表的主页模板index.html。