第一个程序
Flask是基于Python的web开发框架。
从最基本的Flask代码开始吧:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World'
if __name__ == '__main__':
app.run(debug=True)
运行如上代码,就可以在浏览器中看到运行结果——Hello,Flask!
- 第二行调用Flask()构造函数,返回的是一个application对象;
- url ‘/‘绑定到了hello_world()上面;
在上面的示例中,run()方法用于在本地服务器上运行应用程序,其函数原型为:
app.run(host, port, debug, options)host,指定主机端口号
- port,端口号
- debug,是否启用调试模式
Flask路由
在Web应用中,不同的url对应不同的页面;Flask中的route()装饰器用于将URL绑定到函数:
from flask import Flask
app = Flask(__name__)
@app.route('/hello')
def hello_flask():
return 'hello Flask'
if __name__ == '__main__':
app.run(debug=True)
在上面的代码示例中,route()装饰器将URL‘/hello’规则绑定到了hello_flask()函数,如果用户访问
http://localhost:5000/hello ,hello_flask()函数的输出就将在浏览器中呈现。
当然,也可以不使用装饰器写法,改用application对象的add_url_rule()函数也可以实现URL与函数的绑定:
def hello_flask():
return 'hello flask!'
app.add_url_rule('/', 'hello', hello_flask)
Flask变量规则——路由参数
向规则参数添加变量部分,可以动态地构建URL。
此变量部分标记为 < variable-name >
示例:
@app.route('/blog/<int:postId>')
def show_blog(postId):
return 'Blog Number %d' % postId
@app.route('/rev/<float:revNo>')
def revision(revNo):
return 'Revision Number %f' % revNo
< int:postId>中,int是对变量类型postId的限制,我们在地址栏中输入/blog/9后,按下回车,屏幕上就会显示Blog Number 9。
- %d 整型
- %f 浮点型
- %s 字符串型
Flask URL构建
函数url_for(),用于动态构建特定函数的URL。
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/admin')
def hello_admin():
return 'Hello Admin'
@app.route('/guest/<guest>')
def hello_guest(guest):
return 'Hello %s as Guest' % guest
@app.route('/user/<name>')
def hello_user(name):
if name == 'admin':
return redirect(url_for('hello_adminn'))
else:
return redirect(url_for('hello_guest', guest=name))
if __name__ == '__main__':
app.run(debug=True)
在/user/…对应的函数hello_user中,我们作出了处理:
如果接收参数为字符串admin,就重定向到hello_admin()函数否则重定向到hello_guest()函数。
Flask中的HTTP
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="http://localhost:5000/login" method="post">
<p>Enter Name:</p>
<p><input type="text" name="nm" /></p>
<p><input type="submit" value="submit" /></p>
</form>
</body>
</html>
我们创建一个html文件,在其中写一个表单,在下面的文件中接收表单提交到服务器的数据。
# 在Flask中使用HTTP方法
from flask import Flask, redirect, url_for, request
app = Flask(__name__)
@app.route('/success/<name>')
def success(name):
return 'welcome %s' % name
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
# 通过表单拿到输入的名字,并给动态URL
user = request.form['nm']
return redirect(url_for('success', name=user))
else:
user = request.args.get('nm')
return redirect(url_for('success', name=user))
if __name__ == '__main__':
app.run(debug=True)
模板
模板的来历
之前与URL绑定的函数,叫做视图函数,一般来说,视图函数有两个作用:
- 处理业务逻辑(背后的业务代码,也即展示出来的数据是怎么来的)
- 返回相应内容(将要展示的数据表现出来)
在大型应用中,一般选择将业务逻辑与表现内容分开,否则代码极其复杂,维护起来很困难。
因此,我们需要用到模板。
何为模板
模板,其实就是一个包含响应文本的文件,特殊的地方在于,里面有动态文本内容,使用占位符变量来表示,占位符变量可以告诉模板引擎该处的值需要从另外的地方获取数据;
另外,从视图函数中的真实值,替换模板中的占位符变量,这个过程简单理解为“渲染”。
如此一来,模板的使用,就可以将业务逻辑与表现内容分离开来,使得
- 视图函数只负责业务逻辑和数据处理
- 模板只负责从视图函数中获取数据进行展示
举例:
我们在项目中单独创建templates文件夹,并在该目录下创建一个模板文件hello.html;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>05_Flask模板</title>
</head>
<body>
我的模板html内容
<!-- 注意,以下的双括号插值都是待加入的变量,从视图函数中得来 -->
<br />{{ my_str }}
<br />{{ my_int }}
<br />{{ my_array }}
<br />{{ my_dict }}
</body>
</html>
可以发现,模板文件中,占位符处的值需要从视图函数中获取对应的数据,下面是视图函数所在文件:
from flask import Flask, render_template
from sympy import deg
app = Flask(__name__)
# 我们向模板中传入字符串、列表、字典
@app.route('/')
def index():
# 定义要往模板中传递的数据
my_str = 'Hello World'
my_int = 10
my_array = [3, 4, 2, 1, 7, 9]
my_dict = {
'name': 'xiaoming',
'age': 18,
}
return render_template('hello.html',
my_str=my_str,
my_int=my_int,
my_array=my_array,
my_dict=my_dict
)
if __name__ == '__main__':
app.run(debug=True)
控制代码块写法
包括if写法(选择)、for写法(循环)。
演示相关的模板语法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 模板语法,使用{# #}表示注释 -->
{# 判断显示内容 #}
{% if name %}
<!-- janjo模板语法,双括号插值写法,|后面跟一个函数(首字母大写) -->
<h1>hello {{ name|capitalize }}</h1>
{% else %}
<h1>请登录</h1>
<!-- 选择代码块的结束标识 -->
{% endif %}
<!-- for循环的使用 -->
{% for general in my_list %}
{{ general }} <br/>
<!-- 循环代码块的结束标识 -->
{% endfor %}
</body>
</html>
视图函数如下:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/control')
def control():
my_list = ['徐达', '常遇春', '郭英', '蓝玉', '傅友德', '耿炳文']
return render_template('control.html', name='xiaoming', my_list=my_list)
if __name__ == '__main__':
app.run(debug=True)
过滤器
过滤器的本质就是函数。它的作用在于“微调”,即有时候我们需要对模板中的数据做一定的修改,比如更改格式(首字母大写、日期格式等),在模板中自然不能直接调用Python方法,这样一来,就需要用到过滤器。
语法格式如下:
{{ variable | filter_name(*args) }}
variable即为变量,filter_name即为过滤器函数,*args 为过滤器接收的参数
常见的内置过滤器有
- upper:字符串中全部字符大写
- lower:字符串中全部字符小写
- reverse:字符串反转
- format:格式化输出
- first:取列表的首元素
- last:去列表的尾元素
- length:得到列表长度
- sum:得到列表所有元素之和
- sort:列表排序
等等。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% for item in my_list %}
<!-- upper为过滤器,表示将变量item全部大写 -->
{{ item | upper }}
{% endfor %}
</body>
</html>
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def show_filter():
my_list = ['www', 'wanda', 'amazi']
return render_template('filter.html', my_list=my_list)
if __name__=='__main__':
app.run(debug=True)
Flask Request对象
来自客户端网页的数据作为全局请求对象发送到服务器,为了处理请求数据,应该从Flask模块导入。
Request对象的重要属性如下:
- Form:字典对象,包含表单参数及其值的键、值;
- args:解析查询字符串的内容,URL中?之后的部分;
- Cookies:保存Cookie名称和值的字典对象;
- files:与上传文件有关的数据;
- method:当前的请求方法
Web表单
web表单是web应用程序的基本功能。在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且有验证表单数据的功能。
from curses import flash
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
# request对象,里面包含请求的信息,包括请求方式
if request.method == 'POST':
# 获取表单数据
form = request.form
username = form.get('username')
password = form.get('password')
print(password)
if not all([username, password]):
# print('参数不完整')
# 使用消息闪现
flash('参数不完整')
elif password != '123':
# print('密码错误...')
flash('密码错误!')
else:
return 'success'
return render_template('login.html')
if __name__=='__main__':
app.run()
消息闪现flash
在上面的栗子中,我们使用了flash,它代替了print语句,也可以传递消息。
- 视图函数中,我们使用flash,其中参数就是消息内容字符串
- 模板中,使用for循环遍历获取闪现消息
表单数据发送到模板
原生写法
有了前面的知识点,我们接下来研究如何将表单数据发送到模板。
我们的案例中,准备了两个模板文件student.html(收集表单数据)、result.html(展现收集到的表单数据,以表格形式)。
<!-- student.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="http://localhost:5000/result" method="POST">
<p>Name <input type="text" name="Name" /></p>
<p>Physics <input type="text" name="Physics" /></p>
<p>Chemistry <input type="text" name="chemistry" /></p>
<p>Maths <input type="text" name="Mathematics" /></p>
<p><input type="submit" value="submit" /></p>
</form>
</body>
</html>
from flask import Flask, render_template, request
app = Flask(__name__)
# 首先进入/ URL页面,呈现具有表单的网页
@app.route('/')
def student():
return render_template('student.html')
@app.route('/result', methods=['POST', 'GET'])
def result():
if request.method == 'POST':
# 收集字典对象中的request.form中的表单数据,并给result.html
result = request.form
return render_template('result.html', result=result)
if __name__ == '__main__':
app.run(debug=True)
由于student()绑定到URL /页面下,因此首先展示的就是student()中渲染的student.html文件,即展示表单;
而一旦有提交表单的POST请求,就会将请求中的表单数据给模板result.html来渲染。
result.html文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table border=1>
{% for key, value in result.items() %}
<tr>
<th> {{ key }} </th>
<td> {{ value }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
WTF
基本使用
Flask的WTF表单,提供了更加方便的写法:
from flask import Flask, render_template, request, flash
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
app = Flask(__name__)
app.secret_key = 'itheima' # 设置加密密钥
'''
使用WTF实现表单
自定义一个表单类LoginForm
'''
class LoginForm(FlaskForm):
username = StringField(u'用户名:')
password = PasswordField(u'密码:')
submit = SubmitField(u'提交:')
@app.route('/', methods=['GET', 'POST'])
def login():
login_form = LoginForm()
return render_template('wtf.html', form=login_form)
if __name__ == '__main__':
app.run()
模板文件wtf.html内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="">
{{ form.username.label }} {{ form.username }}
{{ form.password.label }} {{ form.password }}
{{ form.submit.label }} {{ form.submit }}
</form>
</body>
</html>
在视图函数所在的.py文件,导入所需要的库之后,需要单独定一个类,并定义出表单所有项,然后将该类的实例对象给渲染函数,便于模板文件中使用。
在模板文件中,我们用FlaskForm继承类的表单项来获取相应的组件,通过其label属性来获取文本标签。可见上面.html栗子。
表单验证
# 开启wtf验证
@app.route('/', methods=['GET', 'POST'])
def login():
login_form = LoginForm()
# 判断请求方式
if request.method == 'POST':
# 获取请求参数
form = request.form
username = form.get('username')
password = form.get('password')
# 验证参数,WTF可以一句话实现所有的校验
if login_form.validate_on_submit():
return 'success!'
else:
flash('参数有误!')
return render_template('wtf.html', form=login_form)
在Flask中使用数据库
Flask Cookie
Request对象包含Cookie的属性