Flask后端笔记
Jinja2模板
基本流程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Template</title>
</head>
<body>
<h1>hello {
{
name }}</h1>
</body>
</html>
@app.route("/")
def index():
return render_template("index.html", name="python")
使用flask 中的render_template渲染模板
变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>name = {
{ name }}</p>
<p>age = {
{ age }}</p>
<p>my_dict: city= {
{ my_dict["city"] }}</p>
<p>my_dict: city= {
{ my_dict.city }}</p>
<p>my_list: {
{ my_list }}</p>
<p>my_list[my_int]: {
{ my_list[my_int] }}</p>
<p>my_list[0] + my_list[1] = {
{ my_list[0] + my_list[1] }}</p>
<p>{
{"hello" + " python" }}</p>
<p>a{
{" flask world " | trim | upper }}a</p>
<hr/>
<p>{
{my_list | li2 }}</p>
<p>{
{my_list | li3 }}</p>
</body>
</html>
# coding:utf-8
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/index")
def index():
data = {
"name": "python",
"age": 18,
"my_dict": {
"city": "sz"},
"my_list": [1, 2, 3, 4, 5],
"my_int": 0
}
return render_template("index.html", **data)
def list_step_2(li):
"""自定义的过滤器"""
return li[::2]
# 注册过滤器
app.add_template_filter(list_step_2, "li2")
@app.template_filter("li3")
def list_step_3(li):
"""自定义的过滤器"""
return li[::3]
if __name__ == '__main__':
app.run(debug=True)
过滤器
字符串过滤器
safe:禁用转义;
<p>{
{ '<em>hello</em>' | safe }}</p>
capitalize:把变量值的首字母转成大写,其余字母转小写;
<p>{
{ 'hello' | capitalize }}</p>
lower:把值转成小写;
<p>{
{ 'HELLO' | lower }}</p>
upper:把值转成大写;
<p>{
{ 'hello' | upper }}</p>
title:把值中的每个单词的首字母都转成大写;
<p>{
{ 'hello' | title }}</p>
trim:把值的首尾空格去掉;
<p>{
{ ' hello world ' | trim }}</p>
reverse:字符串反转;
<p>{
{ 'olleh' | reverse }}</p>
format:格式化输出;
<p>{
{ '%s is %d' | format('name',17) }}</p>
striptags:渲染之前把值中所有的HTML标签都删掉;
<p>{
{ '<em>hello</em>' | striptags }}</p>
支持链式使用过滤器
<p>{
{ “ hello world “ | trim | upper }}</p>
列表过滤器
first:取第一个元素
<p>{
{ [1,2,3,4,5,6] | first }}</p>
last:取最后一个元素
<p>{
{ [1,2,3,4,5,6] | last }}</p>
length:获取列表长度
<p>{
{ [1,2,3,4,5,6] | length }}</p>
sum:列表求和
<p>{
{ [1,2,3,4,5,6] | sum }}</p>
sort:列表排序
<p>{
{ [6,2,3,1,5,4] | sort }}</p>
自定义过滤器
自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器。
方式一:
通过 add_template_filter (过滤器函数, 模板中使用的过滤器名字)
方式二:
通过装饰器 app.template_filter (模板中使用的装饰器名字)
表单
使用Flask-WTF表单扩展,可以帮助进行CSRF验证,帮助我们快速定义表单模板,而且可以帮助我们在视图中验证表的数据
pip install Flask-WTF
不使用Flask-WTF扩展时,表单需要自己处理
#模板文件
<form method='post'>
<input type="text" name="username" placeholder='Username'>
<input type="password" name="password" placeholder='password'>
<input type="submit">
</form>
from flask import Flask,render_template,request
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print username,password
return “success”
else:
return render_template(“login.html”)
使用Flask-WTF扩展
需要设置 SECRET_KEY 的配置参数
模板页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{
{ form.csrf_token }}
{
{ form.user_name.label }}
<p>{
{form.user_name}}</p>
{% for msg in form.user_name.errors %}
<p>{
{msg}}</p>
{% endfor %}
{
{ form.password.label }}
<p>{
{form.password}}</p>
{% for msg in form.password.errors %}
<p>{
{msg}}</p>
{% endfor %}
{
{ form.password2.label }}
<p>{
{form.password2}}</p>
{% for msg in form.password2.errors %}
<p>{
{msg}}</p>
{% endfor %}
{
{form.submit}}
</form>
</body>
</html>
视图函数
#coding=utf-8
from flask import Flask, render_template, redirect, url_for, session
#导入wtf扩展的表单类
from flask_wtf import FlaskForm
#导入自定义表单需要的字段
from wtforms import SubmitField,StringField,PasswordField
#导入wtf扩展提供的表单验证器
from wtforms.validators import DataRequired,EqualTo
app = Flask(__name__)
app.config['SECRET_KEY']='xhosd6f982yfhowefy29f'
#自定义表单类,文本字段、密码字段、提交按钮
# 定义表单的模型类
class RegisterForm(FlaskForm):
"""自定义的注册表单模型类"""
# 名字 验证器/验证器
# DataRequired 保证数据必须填写,并且不能为空
user_name = StringField(label=u"用户名", validators=[DataRequired(u"用户名不能为空")])
password = PasswordField(label=u"密码", validators=[DataRequired(u"密码不能为空")])
password2 = PasswordField(label=u"确认密码", validators=[DataRequired(u"确认密码不能为空"),
EqualTo("password", u"两次密码不一致")])
submit = SubmitField(label=u"提交")
#定义根路由视图函数,生成表单对象,获取表单数据,进行表单数据验证
@app.route("/register", methods=["GET", "POST"])
def register():
# 创建表单对象, 如果是post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中
form = RegisterForm()
# 判断form中的数据是否合理
# 如果form中的数据完全满足所有的验证器,则返回真,否则返回假
if form.validate_on_submit():
# 表示验证合格
# 提取数据
uname = form.user_name.data
pwd = form.password.data
pwd2 = form.password2.data
print(uname, pwd, pwd2)
session["user_name"] = uname
return redirect(url_for("index"))
return render_template("register.html", form=form)
@app.route("/index")
def index():
user_name = session.get("user_name", "")
return "hello %s" % user_name
if __name__ == '__main__':
app.run(debug=True)
WTForms支持的HTML标准字段
字段对象 | 说明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenField | 隐藏文本字段 |
DateField | 文本字段,值为datetime.date格式 |
DateTimeField | 文本字段,值为datetime.datetime格式 |
IntegerField | 文本字段,值为整数 |
DecimalField | 文本字段,值为decimal.Decimal |
FloatField | 文本字段,值为浮点数 |
BooleanField | 复选框,值为True和False |
RadioField | 一组单选框 |
SelectField | 下拉列表 |
SelectMultipleField | 下拉列表,可选择多个值 |
FileField | 文本上传字段 |
SubmitField | 表单提交按钮 |
FormField | 把表单作为字段嵌入另一个表单 |
FieldList | 一组指定类型的字段 |
WTForms常用验证函数
验证函数 | 说明 |
---|---|
DataRequired | 确保字段中有数据 |
EqualTo | 比较两个字段的值,常用于比较两次密码输入 |
Length | 验证输入的字符串长度 |
NumberRange | 验证输入的值在数字范围内 |
URL | 验证URL |
AnyOf | 验证输入值在可选列表中 |
NoneOf | 验证输入值不在可选列表中 |
控制语句
if语句
{% if %} {% endif %}
for语句
{% for item in samples %} {% endfor %}
宏
类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余。
不带参数宏的定义与使用
定义:
{% macro input() %}
<input type="text"
name="username"
value=""
size="30"/>
{% endmacro %}
使用
{
{ input() }}
带参数宏的定义与使用
定义
{% macro input(name,value='',type='text',size=20) %}
<input type="{
{ type }}"
name="{
{ name }}"
value="{
{ value }}"
size="{
{ size }}"/>
{% endmacro %}
使用
{
{ input(value='name',type='password',size=40)}}
将宏单独封装在html文件中
文件名可以自定义macro.html
{% macro input() %}
<input type="text" name="username" placeholde="Username">
<input type="password" name="password" placeholde="Password">
<input type="submit">
{% endmacro %}
在其它模板文件中先导入,再调用
{% import 'macro.html' as func %}
{% func.input() %}
模板继承
与django一致
模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。
{% block top %}``{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。
子模板使用extends指令声明这个模板继承自哪?父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()
父模板:base.html
{% block top %}
顶部菜单
{% endblock top %}
{% block content %}
{% endblock content %}
{% block bottom %}
底部
{% endblock bottom %}
子模板:
{% extends 'base.html' %}
{% block content %}
需要填充的内容
{% endblock content %}
模板继承使用时注意点:
- 不支持多继承。
- 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
- 不能在一个模板文件中定义多个相同名字的block标签。
- 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。
包含(Include)
Jinja2模板中,除了宏和继承,还支持一种代码重用的功能,叫包含(Include)。它的功能是将另一个模板整个加载到当前模板中,并直接渲染。
示例:
include的使用
{\% include 'hello.html' %}
包含在使用时,如果包含的模板文件不存在时,程序会抛出TemplateNotFound异常,可以加上ignore missing关键字。如果包含的模板文件不存在,会忽略这条include语句。
示例:
include的使用加上关键字ignore missing
{\% include 'hello.html' ignore missing %}
宏、继承、包含:
- 宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。
- 继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。
- 宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。
- 包含(include)是直接将目标模板文件整个渲染出来。
Flask中的特殊变量和方法
在Flask中,有一些特殊的变量和方法是可以在模板文件中直接访问的。
config 对象:
config 对象就是Flask的config对象,也就是 app.config 对象。
{
{
config.SQLALCHEMY_DATABASE_URI }}
request 对象:
就是 Flask 中表示当前请求的 request 对象,request对象中保存了一次HTTP请求的一切信息。
request常用的属性如下:
属性 | 说明 | 类型 |
---|---|---|
data | 记录请求的数据,并转换为字符串 | * |
form | 记录请求中的表单数据 | MultiDict |
args | 记录请求中的查询参数 | MultiDict |
cookies | 记录请求中的cookie信息 | Dict |
headers | 记录请求中的报文头 | EnvironHeaders |
method | 记录请求使用的HTTP方法 | GET/POST |
url | 记录请求的URL地址 | string |
files | 记录请求上传的文件 | * |
{
{ request.url }}
url_for 方法:
url_for() 会返回传入的路由函数对应的URL,所谓路由函数就是被 app.route() 路由装饰器装饰的函数。如果我们定义的路由函数是带有参数的,则可以将这些参数作为命名参数传入。
{
{ url_for('index') }}
{
{ url_for('post', post_id=1024) }}
get_flashed_messages方法:
返回之前在Flask中通过 flash() 传入的信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出。
闪现只能看到一次
{% for message in get_flashed_messages() %}
{
{ message }}
{% endfor %}