【Web开发】Flask框架基础知识
本篇主要是黑马程序员的Flask快速入门教程的笔记
Flask简介
Flask诞生于2010年,是用Python语言基于Werkzeug工具箱编写的轻量级Web开发框架。
Flask的常用扩展包:
- Flask-SQLalchemy:操作数据库;
- Flask-migrate:管理迁移数据库;
- Flask-Mail:邮件;
- Flask-WTF:表单;
- Flask-Bable:提供国际化和本地化支持,翻译;
- Flask-script:插入脚本;
- Flask-Login:认证用户状态;
- Flask-OpenID:认证;
- Flask-RESTful:开发REST API的工具;
- Flask-Bootstrap:集成前端Twitter Bootstrap框架;
- Flask-Moment:本地化日期和时间;
- Flask-Admin:简单而可扩展的管理接口的框架
相关文档:
中文文档:http://docs.jinkan.org/docs/flask/
英文文档:http://flask.pocoo.org/docs/0.12/
Flask安装
pip install flask
- 1
我安装的版本是Flask 2.1.3
拓展命令:
将当前环境打包成requirements.txt
:
pip freeze >requirements.txt
- 1
将需要的环境一起安装:
pip install -r requirements.txt
- 1
基本框架
在Pycharm中,可以直接新建一个Flask模板文件,运行后,可以在浏览器在中输出Hello World。
相关注释如下:
from flask import Flask
# 指向程序所在的模块
app = Flask(__name__)
# 将路由映射到视图函数index
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
# 启动WEB服务器
app.run()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
路由请求方式限定
默认情况下,路由仅支持Get请求方式,可用下
@app.route('/', methods=['GET', 'POST'])
def hello_world():
return 'Hello World!'
- 1
- 2
- 3
路由传递参数
在路由中使用<>可以传递参数,使用int可以限定整形数据
@app.route('/orders/<int:order_id>')
def order(order_id):
print(type(order_id)) # 类型为int
return 'this is order %d' % order_id
- 1
- 2
- 3
- 4
Jinja2模板引擎
Jinja2:是Python下一个被广泛应用的模板引擎,是Flask内置的模板语言。
简单使用
Jinja2提供了render_template函数,来渲染html文件。
下面简单来使用一下:
先导入render_template
from flask import Flask, render_template
- 1
在templates文件夹下新建index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
测试Jinja2
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
进行调用
@app.route('/', methods=['GET', 'POST'])
def index():
return render_template('index.html')
- 1
- 2
- 3
注释
使用 {# #} 进行可以进行注释
变量/控制语句
在路由函数里,可以自定义变量,然后在render_template
函数中进行参数传递,例如:
@app.route('/', methods=['GET', 'POST'])
def index():
my_list = [1, 2, 3, 4, 5]
return render_template('index.html', num_list=my_list)
- 1
- 2
- 3
- 4
num_list对应html文件中的变量。
在html中循环输出:
index.html:
<body>
{% for num in num_list %}
{{ num }}
{% endfor %}
</body>
- 1
- 2
- 3
- 4
- 5
小技巧:先写for,再按Tab可使用代码补全
输出效果:
过滤器
过滤器即Flask提供的一些函数,可以直接进行调用简化操作。
例如:使用lower
可以实现字符串转小写, 使用length
可以获取列表长度。
输入:
<body>
{#字符串转小写#}
<p>{{ 'HELLO' | lower }}</p>
{#获取列表长度#}
<p>{{ [1,2,3,4,5,6] | length }}</p>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
输出:
注:使用连续的|
可以同时使用多个过滤器
更多过滤器总结:
字符串操作
- safe:禁用转义
<p>{{ '<em>hello</em>' | safe }}</p>
- 1
- capitalize:把变量值的首字母转成大写,其余字母转小写
<p>{{ 'hello' | capitalize }}</p>
- 1
- lower:把值转成小写
<p>{{ 'HELLO' | lower }}</p>
- 1
- upper:把值转成大写
<p>{{ 'hello' | upper }}</p>
- 1
- title:把值中的每个单词的首字母都转成大写
<p>{{ 'hello' | title }}</p>
- 1
- reverse:字符串反转
<p>{{ 'olleh' | reverse }}</p>
- 1
- format:格式化输出
<p>{{ '%s is %d' | format('name',17) }}</p>
- 1
- striptags:渲染之前把值中所有的HTML标签都删掉
<p>{{ '<em>hello</em>' | striptags }}</p>
- 1
- truncate: 字符串截断
<p>{{ 'hello every one' | truncate(9)}}</p>
- 1
列表操作
- first:取第一个元素
<p>{{ [1,2,3,4,5,6] | first }}</p>
- 1
- last:取最后一个元素
<p>{{ [1,2,3,4,5,6] | last }}</p>
- 1
- length:获取列表长度
<p>{{ [1,2,3,4,5,6] | length }}</p>
- 1
- sum:列表求和
<p>{{ [1,2,3,4,5,6] | sum }}</p>
- 1
- sort:列表排序
<p>{{ [6,2,3,1,5,4] | sort }}</p>
- 1
语句块过滤
{% filter upper %}
一大堆文字
{% endfilter %}
- 1
- 2
- 3
Flask-WTF表单
在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且它有验证表单数据的功能
以最常见的登录验证为例,这里以普通实现方式和WTF表单方式实现进行比较。
普通方式
html
<form method="post">
<label>用户名:</label><input type="text" name="username"><br>
<label>密码:</label><input type="password" name="password"><br>
<label>确认密码:</label><input type="password" name="password2"><br>
<input type="submit" value="提交"><br>
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
</form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
app.py
from flask import Flask, render_template, request, flash
# 指向程序所在的模块
app = Flask(__name__)
# Flask-WTF需要配置参数SECRET_KEY
app.secret_key = 'zstar'
@app.route('/', methods=['GET', 'POST'])
def hello_world():
# 1. 判断请求方式是post
if request.method == 'POST':
# 2. 获取参数, 并效验参数完整性, 如果有问题就进行flash
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
if not all([username, password, password2]):
flash('params error')
# 3. 效验密码
elif password != password2:
flash('password error')
# 4. 没有问题就返回'success'
else:
print(username)
return 'success'
return render_template('index.html')
if __name__ == '__main__':
# 启动WEB服务器
app.run()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
代码说明:
后端使用request.form.get
的来获取前端表单数据
验证主要来验证两次登录输入密码是否一致
提示信息使用flash
来进行映射,前端使用get_flashed_messages
来获取映射的信息。
WTF表单方式
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{#设置csrf_token(python3版本不需要)#}
{{ form.csrf_token() }}
{{ form.username.label }}{{ form.username }}<br>
{{ form.password.label }}{{ form.password }}<br>
{{ form.password2.label }}{{ form.password2 }}<br>
{{ form.input }}<br>
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
</form>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
app.py
from imp import reload
from flask import Flask, render_template, request, flash
# 导入wtf扩展的表单类
from flask_wtf import FlaskForm
# 导入自定义表单需要的字段
from wtforms import SubmitField, StringField, PasswordField
# 导入wtf扩展提供的表单验证器
from wtforms.validators import DataRequired, EqualTo
# # 解决编码问题
# import sys
# reload(sys)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'zstar'
# 自定义表单类,文本字段、密码字段、提交按钮
# 需要自定义一个表单类
class RegisterForm(FlaskForm):
username = StringField('用户名:', validators=[DataRequired()])
password = PasswordField('密码:', validators=[DataRequired()])
password2 = PasswordField('确认密码:', validators=[DataRequired(), EqualTo('password', '密码输入不一致')])
input = SubmitField('提交')
# 定义根路由视图函数,生成表单对象,获取表单数据,进行表单数据验证
@app.route('/form', methods=['GET', 'POST'])
def form():
register_form = RegisterForm()
if request.method == 'POST':
# 调用validate_on_submit方法, 可以一次性执行完所有的验证函数的逻辑
if register_form.validate_on_submit():
# 进入这里就表示所有的逻辑都验证成功
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
print(username)
return 'success'
else:
flash('参数有误')
return render_template('index.html', form=register_form)
if __name__ == '__main__':
# 启动WEB服务器
app.run()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
代码说明:
使用WTF表单方式的好处是对于密码一致性的不再需要单独进行验证,而是在后端直接将表单封装了成了一个类。
其中,StringField
指定了表单提交的数据类型为String,DataRequired
表明该项为必填项,EqualTo
封装了两个表单的一致性比较过程,最后调用register_form.validate_on_submit
来一次性提交所有的验证逻辑。
前端方面,通过form
可以直接对接到后端定义的表单属性,其中python2需要添加 {{ form.csrf_token() }}
来指定表单的token,在python3版本中,实测不需要该语句也能运行。
WTForms支持的HTML标准字段有下面这些:
字段对象 | 说明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenField | 隐藏文件字段 |
DateField | 文本字段,值为datetime.date文本格式 |
DateTimeField | 文本字段,值为datetime.datetime文本格式 |
IntegerField | 文本字段,值为整数 |
DecimalField | 文本字段,值为decimal.Decimal |
FloatField | 文本字段,值为浮点数 |
BooleanField | 复选框,值为True和False |
RadioField | —组单选框 |
SelectField | 下拉列表 |
SelectMutipleField | 下拉列表,可选择多个值 |
FileField | 文件上传字段 |
submitField | 表单提交按钮 |
FormField | 把表单作为字段嵌入另—个表单 |
FieldList | —组指定类型的字段 |
WTForms常用验证函数:
验证函数 | 说明 |
---|---|
DataRequired | 确保字段中有数据 |
EqualTo | 比较两个字段的值,常用于比较两次密码输入 |
Length | 验证输入的字符串长度 |
NumberRange | 验证输入的值在数字范围内 |
URL | 验证URL |
AnyOf | 验证输入值在可选列表中 |
NoneOf | 验证输入值不在可选列表中 |
数据库
在flask中,可以利用SQLAlchemy来进行数据库的操作。
SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。
flask-sqlalchemy安装
pip install flask-sqlalchemy
pip install mysqlclient
- 1
- 2
直接安装mysqlclient可能会安装失败,我去官网下了轮子:
mysqlclient-1.4.6-cp37-cp37m-win_amd64:https://pan.baidu.com/s/1TiLRPUWjQc8HS7ELlGcxHw?pwd=8888
安装mysql
安装mysql可以参阅这篇博文:Windows10安装MySQL傻瓜式教程(图文教程)
使用下面的命令可以启动/停止mysql服务
# 停止mysql服务
net stop mysql57
# 启动mysql服务
net start mysql57
- 1
- 2
- 3
- 4
安装好之后,可以通过Navicat连接本地数据库进行可视化:
使用示例
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
class Config(object):
"""配置参数"""
# sqlalchemy的配置参数
SQLALCHEMY_DATABASE_URI = "mysql://root:你的密码@127.0.0.1:3306/zstar"
# 设置sqlalchemy自动更跟踪数据库
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
# 连接数据库
app.config.from_object(Config)
# 创建数据库aqlalchemy工具对象
db = SQLAlchemy(app)
class Role(db.Model):
# 定义表名
__tablename__ = 'roles'
# 定义列对象
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), unique=True)
user = db.relationship('User', backref='role')
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), unique=True, index=True)
email = db.Column(db.String(32), unique=True)
password = db.Column(db.String(32))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
@app.route("/")
# 第一种查询方式
from sqlalchemy import text
sql = text("select * from roles")
result = db.engine.execute(sql)
for row in result:
print(row)
# 第二种查询方式
# print(Role.query.all())
# print(Role.query.filter_by(id=2).first())
@app.route("/create")
def create():
role1 = Role(name="admin")
# session记录对象任务
db.session.add(role1)
# 提交任务到数据库中
db.session.commit()
return "The Role is created"
# 创建表:
# db.create_all()
# 删除表
# db.drop_all()
if __name__ == '__main__':
app.run()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
本例中,首先需要手动创建数据库zstar
,然后配置数据库连接ip和账号密码mysql://root:你的密码@127.0.0.1:3306/zstar
,之后使用db.create_all()
会创建前面定义出的数据表,同理db.drop_all()
会删除前面定义出的数据表。这两句实测必须放在if __name__ == '__main__':
外面,否则不会被运行,未知具体原因。
本例中,我定义了两个接口,第一个根目录接口,分别尝试了通过sql
来从直接查询和调用对象进行查询的两种查询方式,第二个/create接口,实现了向数据表Role
中插入一个名称为admin的用户数据。
文章来源: zstar.blog.csdn.net,作者:zstar-_,版权归原作者所有,如需转载,请联系作者。
原文链接:zstar.blog.csdn.net/article/details/126015400
- 点赞
- 收藏
- 关注作者
评论(0)