Flask 2 框架进阶

一 请求与响应

请求属性与方法

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
request.method 请求方法 request.args get请求提交的数据 request.form post请求提交的数据 request.values post和get提交的数据总和 request.cookies 客户端所带的cookie request.headers 请求头 request.path 不带域名,请求路径 request.full_path 不带域名,带参数的请求路径 request.url 带域名带参数的请求路径 request.base_url 带域名请求路径 request.url_root 域名 request.host_url 域名 request.host 127.0.0.1:500 request.files 请求提交的文件

requst对象的常用方法

request对象使用需要从flask模块中导入

复制代码
  • 1
Copyfrom flask import Flask, request

使用request属性获取url

属性 解析值 属性 解析值
path u‘/student_list/’ base_url u'http://127.0.0.1:5000/student_list/'
full_path u‘/student_list/?name=mark’ url u'http://127.0.0.1:5000/student_list/?name=mark'
host u'127.0.0.1:5000' url_root u'http://127.0.0.1:5000/'
host_url u'http://127.0.0.1:5000/'

request的解析结果如下。

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
Copy@app.route('/student_list/') def student_list(): print(request.path) # 输出 /student_list/ print(request.full_path) # 输出 /student_list/?name=mark print(request.host) # 输出 127.0.0.1:5000 print(request.host_url) # 输出 http://127.0.0.1:5000/ print(request.base_url) # 输出 http://127.0.0.1:5000/student_list/ print(request.url) # 输出 http://127.0.0.1:5000/student_list/?name=mark print(request.url_root) # 输出 http://127.0.0.1:5000/ return 'request.urldemo测试'

其他request对象常用的属性和方法。

GET和POST:

常见的HTTP方法:

请求 说明 请求 说明
GET 获取服务器资源 DELETE 删除服务器资源
POST 处理服务器资源 PATCH 在服务器更新资源(客户端提供改变的属性)
PUT 在服务器更新资源(客户端提供改变后的完整资源)

一般常用的请求为GET和POST

GET请求:

GET请求一般用于在服务器上获取资源,不会更改服务器的状态。

GET实例

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
Copy@app.route('/', methods=['GET']) # 不写methods也可以 默认就接收get请求 def demo_get(): print(request.args.get('name')) # 输出 mark return '{}请求'.format(request.method)

结合request对象,使用request.args属性获取get传来的参数

关键词

  • 使用request.args属性获取get传来的参数,
  • @app.route('/', methods=['GET']) 指定浏览器只能以GET方法访问服务端。

POST请求:

POST 请求: 会给服务器提交一些数据或者文件,会对服务器的状态产生影响。

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
Copyfrom flask import Flask, request, render_template import config app = Flask(__name__) @app.route('/login_request/',methods=['POST']) def login_request(): print(request.form.get('username')) # 'mark' print(request.form.get('password')) # '123' if request.form.get('username') == 'mark' and request.form.get('password') == '123': return 'success' else: return 'error' @app.route('/login/',methods=['GET']) def login(): return render_template('login.html') if __name__ == '__main__': app.run()

关键词

  • request.form是专门用来针对表单取数据的,在这里如果前端是以表单的形式提交的,我们可以使用request.form来取值
  • @app.route() 中的 methods=['POST'] 代表只接收浏览器的POST请求

templates/login.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录界面</title> </head> <body> <form action="/login_request/" method="POST"> 用户:<input type="text" name="username"> 密码:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html>

总体的逻辑是 :

  1. 首先访问127.0.0.1:5000/login/,默认是get请求。
  2. 然后return render_template('login.html') 返回给浏览器页面。
  3. 然后填写内容点击提交,以post方式请求 http://127.0.0.1:5000/login_request/。
  4. 然后进入def login_request()视图函数 进行逻辑判断返回成功与否。

一个视图函数同时可以接收GET和POST请求

实例:

server.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
Copyfrom flask import Flask, request, render_template import config app = Flask(__name__) @app.route('/login_inner/',methods=['POST','GET']) def login_inner(): if request.method == 'GET': #判断本次请求是否为get请求 return render_template('login.html') if request.form.get('username') == 'mark' and request.form.get('password') == '123': return 'success' return 'error' if __name__ == '__main__': app.run(debug=True)

关键词

  • @app.route()methods方法 指定该视图函数接收浏览器传过来的请求方法,可以指定多个。
  • request.method获取字符串格式的请求方法

templates/login.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录界面</title> </head> <body> <form action="" method="POST"> 用户:<input type="text" name="username"> 密码:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html>

请求扩展方法

复制代码
  • 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
类似于django的中间件,请求来时,请求走时,做什么操作 # 1 请求来了就会触发,类似于django的process_request,如果有多个,顺序是从上往下 @app.before_request def before(*args,**kwargs): if request.path=='/login': return None else: name=session.get('user') if not name: return redirect('/login') else: return None # 2 请求走了就会触发,类似于django的process_response,如果有多个,顺序是从下往上执行 @app.after_request def after(response): print('我走了') return response #3 before_first_request 项目启动起来第一次会走,以后都不会走了,也可以配多个(项目启动初始化的一些操作) @app.before_first_request def first(): print('我的第一次') # 4 每次视图函数执行完了都会走它,# 用来记录出错日志 @app.teardown_request # 用来记录出错日志 def ter(e): print(e) print('我是teardown_request ') # 5 errorhandler绑定错误的状态码,只要码匹配,就走它 @app.errorhandler(404) def error_404(arg): return render_template('error.html',message='404错误') # 6 全局标签 @app.template_global() def sb(a1, a2): return a1 + a2 # 在模板中:{{ sb(3,4) }} # 7 全局过滤器 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 # 在模板中{{ 1|db(2,3)}} 1 重点掌握before_request和after_request, 2 注意有多个的情况,执行顺序 3 before_request请求拦截后(也就是有return值),response所有都执行

二 视图函数和视图类

视图函数

基本用法与Django的视图函数类似,返回结果时需要注意

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
# 响应格式 # return "字符串" # return render_template('html模板路径',**{}) # return redirect('/index.html') # django有JsonResponse对应的flask有jsonify # return jsonify({'k1':'v1'}) 设置cookie aa='hello world' res=make_response(aa) res.set_cookie('xxx','lqz') 往响应头中放属性 res.headers['X-Something'] = 'A value'

反向解析

url_for()的使用

当设置别名时url_for()会根据别名调用视图函数

复制代码
  • 1
url_for('视图函数名字') # 输出该视图函数url

具体例子

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
from flask import Flask,url_for app = Flask(__name__) app.config.update(DEBUG=True) @app.route('/') def demo1(): print(url_for("book")) # 注意这个引用的是视图函数的名字 字符串格式 print(type(url_for("book"))) return url_for("book") @app.route('/book_list/') def book(): return 'flask_book' if __name__ == "__main__": app.run()

视图函数如果需要参数,在使用url_for调用时传入所需的参数

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
@app.route('/demo2/') def demo2(): student_url = url_for('student', id=5, name='mark') # id 就是动态path的key 必须赋值, # name 将作为查询字符串传入 print(student_url) return student_url @app.route('/student/<int:id>/') def student(id): return 'student {}'.format(id)

视图函数添加自定义装饰器

我们在平时的开发的过程中,很多需要权限验证的功能需要用到装饰器,下面的代码是如何在flask中实现一个装饰器。

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
from flask import Flask, request from functools import wraps app = Flask(__name__) def login_verify(func): @wraps(func) def wrapper(*args, **kwargs): user_name = request.args.get('user') password = request.args.get('password') if user_name == 'mark' and password == '123': return func(*args,**kwargs) else: return '请登录' return wrapper @app.route('/') def hello_world(): return 'Hello World!' @app.route('/my_info/') @login_verify def my_info(): return '个人信息页面'

关键词

  1. 装饰器一定要写在注册路由的下面,写在视图函数的上面。
  2. 装饰器内部一定要使用@wraps(func)方法,用于保护被装饰函数的属性。

视图类

视图类的基本用法

复制代码
  • 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
from flask import Flask, views, request, url_for from functools import wraps def login_verify(func): @wraps(func) def wrapper(*args, **kwargs): user_name = request.args.get('user') password = request.args.get('password') if user_name == 'mark' and password == '123': return func(*args,**kwargs) else: return '请登录' return wrapper class CBVTest(views.MethodView): methods = ['GET','POST'] # 指定可以接收的方法有什么 decorators = [login_verify,] # 指定自定义的装饰器 def get(self): print(url_for('cbvtest')) return 'cbv_get' def post(self): return 'cbv_post' app.add_url_rule('/cbvtest',view_func=CBVTest.as_view(name='cbvtest'),endpoint='end_demo')

详解:

  1. 首先从flask中导入 views

  2. 写一个类一定要继承 views.MethodView

  3. 在类中写methods = ['GET','POST'] 可以指定可接受的请求类型

  4. 在类中写decorators = [login_verify,]可以指定装饰器,第一个装饰器是最里层函数依次往后包裹

  5. 在类中写def get(self):用于获取get请求

  6. 在类中写def post(self):用于获取post请求

  7. 添加路由的方法使用

    复制代码
    • 1
    • 2
    app.add_url_rule( '路由',view_func=CBVTest.as_view(name='自定义一个端点名字'))

    其原理是CBVTest.as_view(name='自定义一个端点名字')会返回一个函数,name是为这个函数命的名字,可以通过这个函数进行分发请求等操作。

三 flask模板引擎jinja2

模板引擎

实现视图的业务逻辑和返回给前端的页面逻辑分离的工具,我们称之为模板引擎。

模板可以理解为一个特殊的html文件,特殊之处就在于这个html文件包含固定内容和动态部分,其动态部分可以借助模板引擎进行传参

模板引擎帮我们分开了业务逻辑和页面逻辑,并且我们每次修改一个大字符串会非常不方便。模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,然后返回给浏览器,这个过程我们称之为渲染。

作用:辑和页面逻辑的分离,实现了动态的去渲染页面。

Flask使用jinja2作为框架的默认模板引擎,Jinja2是基于python的模板引擎,功能比较类似于于PHPsmartyJ2eeFreemarkervelocityJinja2除了设置变量,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板的输出。并且jinja2不限制模板的格式为html,可以是任何格式的文本文件。

模板举例:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录界面</title> </head> <body> <h1>login01</h1> <!--login02.html文件的这一行的内容是:‘ <h1>login02</h1> ’ --> <form action="" method="POST"> 用户:<input type="text" name="username"> 密码:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html>

模板引擎传参

模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,这个步骤我们就称之为模板引擎传参。

我们传参的时候要应用render_template()利用render_template的第二个参数进行传参,该函数在定义时候,第二个参数是可变长形参,所以在传值的时候我们可以传入多个关键字实参。

在模板中接收的时候使用{{}}包裹参数进行接收。

传参举例:

server.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
def demo2(): context_dict = {"name": "mark", "age": "mark", "sex": "girl", "other_info":{"tel":1365, "qq":565656}} return render_template('index.html',**context_dict)

index.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板传参</title> </head> <body> {{name}} {{age}} {{sex}} {{other_info.tel}} {{other_info["qq"]}} </body> </html>

在视图函数中

  • render_template传参的时候以关键字实参进行传参。可以传多个,可以用**讲字典打散成关键字实参。

在模板中

  • jinja2模板引擎支持接收变量在用 {{}}包裹参数进行接收
  • 并且如果发现是字典,可以用.字典里面的key取出value值。也可以直接字典跟[]进行取值。

模板中反向解析

server.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
@app.route('/') def index(): return render_template('index.html', name="mark", age=18) @app.route('/info/') def info(): return render_template('info.html')

info.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>信息页面</title> </head> <body> <h1>这是信息页面</h1> </body> </html>

index.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板传参</title> </head> <body> <a href="/info/">正常跳转</a> <a href="{{ url_for('info') }}">urlfor跳转</a> </body> </html>
  • url_for 在视图函数中如何使用,在模板中同样的用法。
  • 支持翻转查询字符串
  • 支持动态路由翻转

jinja2中控制语句

在jinja2中用{% %}特殊符号来编辑控制语句,一个语句以{% ... %}为起始 并且以{% end... %}来标记结束。

逻辑语句

可以使用> , < , <=, ==,!=,进行判断,

也可以使用 and,or,not,()来进行逻辑合并

server.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Copy... @app.route('/') def hello_world(): context_dict = { 'age': 17, 'sex': 'man', } return render_template('index.html',**context_dict) ...

index.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jinja2分支</title> </head> <body> {% if sex == 'man' %} <p>男人</p> {% else %} <p>女人</p> {% endif %} {% if age > 18 %} <p>成年人</p> {% elif age == 18 %} <p>刚刚成年</p> {% else %} <p>未成年</p> {% endif %} </body> </html>

循环语句

for循环可以便利任何一个可迭代对象,包括列表、字典等,支持反向遍历

列表循环:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
{% for country in countrys%} <p>{{ country }}</p> {% else %} <p>没有值</p> {% endfor %}

sever.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
Copy@app.route('/') def hello_world(): context_dict = { 'countrys':["1-china","2-America","3-French"] } return render_template('index.html',**context_dict)

index.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>for循环</title> </head> <body> {% for country in countrys %} {# {% for country in countrys|reverse %} 可以实现反向遍历#} <p>{{ country }}</p> {% else %} <p>没有值</p> {% endfor %} </body> </html>

反向遍历实例

复制代码
  • 1
server.py`的 `{% for country in countrys %}` 改为 `{% for country in countrys|reverse %}

字典循环

sever.py

复制代码
  • 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
Copy@app.route('/') def hello_world(): context_dict = { 'countrys':["1-china","2-America","3-French"] } return render_template('index.html',**context_dict) @app.route('/demo/') def demo(): context_dict ={ 'colleges':[ { 'name': '清华大学', 'area': '北京' }, { 'name': '复旦大学', 'area': '上海' '' }, { 'name': '吉林大学', 'area': '吉林' }, { 'name': '中山大学', 'area': '广东' } ] } return render_template('index.html',**context_dict)

index.html

复制代码
  • 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
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>for循环</title> </head> <body> <table> <tr> <th>1开始的序号</th> <th>0开始的序号</th> <th>大学名称</th> <th>所属地区</th> <th>总数</th> </tr> {% for college in colleges %} {% if loop.first %} <tr style="background: blue"> {% elif loop.last %} <tr style="background: yellow "> {% else %} <tr> {% endif %} <td>{{ loop.index }}</td> <td>{{ loop.index0 }}</td> <td>{{ college.name }}</td> <td>{{ college.area }}</td> <td>{{ loop.length }}</td> </tr> {% endfor %} </table> </body> </html>

for循环常用变量表

for循环常用变量 功能描述
loop.index 当前循环的索引(从1开始)
loop.index0 当前循环的索引(从0开始)
loop.first 是否是第一次循环,是返回True,否则返回Flase
loop.last 是否是最后一次循环,是返回True,否则返回Flase
loop.length 总共可以循环的次数 / 迭代器的长度

for循环中的else用法

for还可以else分支语法,如果for内部没有遍历出来内容,那么就会走else分支,反之如果for循环遍历出了内容,则不会运行else分支。

注意:jinja2中的forelse逻辑不通于python在此不要类比python中的 forelse

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
Copy{% for country in countrys|reverse %} <p>{{ country }}</p> {% else %} <p>没有值</p> {% endfor %}

模板加载静态文件

在模板中加载静态文件的时候也要使用到url_for()函数,去寻找具体的静态文件资源。第一个参数是定位到static文件夹,filename参数定位到static文件夹内的具体资源。

复制代码
  • 1
Copy{{ url_for('static',filename='相对于static文件夹的路径') }}

项目目录:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Copy│ app.py │ ├─static # 文件夹 │ ├─css # 文件夹 │ │ demo.css │ │ │ ├─images # 文件夹 │ │ 1.png │ │ │ └─js # 文件夹 │ demo.js │ ├─templates # 文件夹 index.html

app.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
@app.route('/') def hello_world(): return render_template('index.html')

index.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>静态文件加载</title> <link rel="stylesheet" href="{{ url_for('static',filename='css/demo.css') }}"> <script src="{{ url_for('static',filename='js/demo.js') }}"></script> </head> <body> <img src="{{ url_for('static',filename='images/1.png') }}"> </body> </html>

demo.css

复制代码
  • 1
  • 2
  • 3
body{ background: red; }

demo.js

复制代码
  • 1
alert('hello world')

模板的继承

jinja2的模板继承可以把一些公共的代码定义到一个基模板中,比如把导航栏、页脚等通用内容放在基模板中,以后所有的子模板直接继承基模板,在子模板被渲染时会自动包含继承基模板的内容,通过模板的继承可以避免在多个模板中编写重复的代码。

在基模板中定义一些公共的代码,子模板会继承这些公共的代码,但是子模板需要根据自己的需求去实现不同的代码,这个时候就需要在基模板中提供一些接口,以便子模板实现自己的业务需求。

1 基本写法

在基/父模板中定义接口(block)

复制代码
  • 1
  • 2
  • 3
Copy{% block main %} {# main是自定义的变量名 #} {% endblock %}

在子模板中继承父模板,并且重写接口(block)

复制代码
  • 1
  • 2
  • 3
  • 4
Copy{% extends 'base.html' %} {# extends 后面跟的参数是导入的基模板相对于templates的路径 #} {% block main %} {% endblock %}

2 子模板中调用父模板代码block中的代码

基模板中

复制代码
  • 1
  • 2
  • 3
  • 4
Copy{% block main %} <p>父模板中main中原有的内容</p> {% endblock %}

子模板中:

复制代码
  • 1
  • 2
  • 3
  • 4
Copy{% block main %} {{ super() }} {# 保留基模板中本块的代码 #} <p>子模板中重写main的内容 </p> {% endblock %}

3 在子模板中调用其他block中的代码:

子模板中:

复制代码
  • 1
  • 2
  • 3
  • 4
Copy{% block main %} {{ self.demo() }} {# self.其他block名字 #} <p>子模板中重写main的内容 </p> {% endblock %}

4 子模板中的想定义自己的代码只能放到block中,否则无效

项目目录

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
Copy│ app.py │ ├─static # 文件夹 │ └─css │ bootstrap-theme.css │ bootstrap-theme.css.map │ bootstrap-theme.min.css │ bootstrap-theme.min.css.map │ bootstrap.css │ bootstrap.css.map │ bootstrap.min.css │ bootstrap.min.css.map │ ├─templates # 文件夹 base.html detail.html

css文件夹: 是从我们上面下载好的用于生产环境的 Bootstrap中解压出来的

base.html 注意:里面的form标签中的内容和nav标签中的内容均是bootstrap框架的代码截取,div标签是用于清除浮动

复制代码
  • 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
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父模板</title> <link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.css') }}"> </head> <body> <form class="navbar-form navbar-left" role="search"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <div style=" visibility:hidden;display:block;font-size:0;clear:both; height:50px"></div> {% block main %} <p>父模板中main中原有的内容</p> {% endblock %} <br> <br> <br> {% block demo %} <p>demo中原有的内容</p> {% endblock %} <div style=" visibility:hidden;display:block;font-size:0;clear:both; height:0"></div> <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">&laquo;</span> </a> </li> <li><a href="#">1</a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">&raquo;</span> </a> </li> </ul> </nav> </body> </html>

detail.html

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Copy{% extends 'base.html' %} {% block demo %} <p>子模板中重写demo的内容</p> {% endblock %} {% block main %} {{ super() }} {# 保留基模板中本block的代码 #} {{ self.demo() }} {# 调用demo block的代码 #} <p>子模板中重写main的内容 </p> {% endblock %}

app.py 注意:app.config.update(TEMPLATES_AUTO_RELOAD=True)语句用于每次都重新加载模板文件

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
Copyfrom flask import Flask, render_template app = Flask(__name__) app.config.update(TEMPLATES_AUTO_RELOAD=True) @app.route('/') def hello_world(): return render_template('base.html') @app.route('/demo/') def demo(): return render_template('detail.html') if __name__ == '__main__': app.run()

闪现

Flask 提供了一个非常简单的方法来使用闪现系统向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息,然后在且仅仅在下一个请求中访问这个数据,强调flask闪现是基于flask内置的session的,利用浏览器的session缓存闪现信息。所以必须设置secret_key

server.py

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
Copyfrom flask import Flask, flash, redirect, render_template, \ request, url_for app = Flask(__name__) app.secret_key = 'some_secret' @app.route('/') def index(): return render_template('index.html') @app.route('/login', methods=['GET', 'POST']) def login(): error = None if request.method == 'POST': if request.form['username'] != 'admin' or \ request.form['password'] != '123': error = '登录失败' else: flash('恭喜您登录成功') return redirect(url_for('index')) return render_template('login.html', error=error) if __name__ == "__main__": app.run()

注意:这个 flash() 就可以实现在下一次请求时候,将括号内的信息做一个缓存。不要忘记设置secret_key

这里是 index.html 模板:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
Copy{% with messages = get_flashed_messages() %} # 获取所有的闪现信息返回一个列表 {% if messages %} <ul class=flashes> {% for message in messages %} <li>{{ message }}</li> {% endfor %} </ul> {% endif %} {% endwith %} <h1>主页</h1> <p>跳转到登录页面<a href="{{ url_for('login') }}">登录?</a>

注意:{% with messages = get_flashed_messages() %} # 获取所有的闪现信息返回一个列表

这里是login.html 模板

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
Copy<h1>登录页面</h1> {% if error %} <p class=error><strong>Error:</strong> {{ error }} {% endif %} <form action="" method=post> 用户名: <input type=text name=username> 密码: <input type=password name=password> <p><input type=submit value=Login></p> </form>

简单的在模板中实现获取闪现信息小结:

复制代码
  • 1
  • 2
设置闪现内容:flash('恭喜您登录成功') 模板取出闪现内容:{% with messages = get_flashed_messages() %}

模板中的分类闪现

当闪现一个消息时,是可以提供一个分类的。未指定分类时默认的分类为 'message' 。 可以使用分类来提供给用户更好的反馈,可以给用户更精准的提示信息体验。

要使用一个自定义的分类,只要使用 flash() 函数的第二个参数:

复制代码
  • 1
  • 2
flash('恭喜您登录成功',"status") flash('您的账户名为admin',"username")

在使用get_flashed_messages()时候需要传入with_categories=true便可以渲染出来类别

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} <ul class=flashes> {% for category, message in messages %} <li class="{{ category }}">{{ category }}:{{ message }}</li> {% endfor %} </ul> {% endif %} {% endwith %}

模板中的分类闪现小结:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
分类设置闪现内容:flash('恭喜您登录成功',"status") flash('您的账户名为admin',"username") 模板取值: {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} <ul class=flashes> {% for category, message in messages %} ...

模板中过滤闪现消息

同样要使用一个自定义的分类,只要使用 flash() 函数的第二个参数:

复制代码
  • 1
  • 2
flash('恭喜您登录成功',"status") flash('您的账户名为admin',"username")

在使用get_flashed_messages()时候需要传入category_filter=["username"]便可根据类别取出闪现信息。中括号内可以传入的值就是类别,可以传入多个。

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
{% with messages = get_flashed_messages(category_filter=["username"]) %} {% if messages %} <ul> {%- for message in messages %} <li>{{ message }}</li> {% endfor -%} </ul> </div> {% endif %} {% endwith %}

小结:

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
分类设置闪现内容:flash('恭喜您登录成功',"status") flash('您的账户名为admin',"username") 模板取值: % with messages = get_flashed_messages(category_filter=["username"]) %} {% if messages %} <ul> {%- for message in messages %}

视图中获取闪现信息

复制代码
  • 1
  • 2
  • 3
-设置: flash('xxx') -取值:get_flashed_message() # 注意这个不同于模板取值,这个是从flask中导入的 -注意:在视图中获取闪现信息不必非得是两次连续的请求,只要保证是第一次取相应的闪现信息,就可以取得到。

实例:

复制代码
  • 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
from flask import Flask, request, flash, get_flashed_messages import os app = Flask(__name__) app.secret_key = os.urandom(4) app.debug = True @app.route('/login/') def login(): if request.args.get('name') == 'rocky': return 'ok' flash('第一条闪现信息:用户名不是rocky填写的是{}'.format(request.args.get('name'))) # flash('第二条闪现信息:用户名不是rocky填写的是{}'.format(request.args.get('name'))) return 'error,设置了闪现' @app.route('/get_flash/') def get_flash(): #get_flashed_messages()是一个列表列表可以取出闪现信息,该条闪现信息只要被取出就会删除掉。 return '闪现的信息是{}'.format(get_flashed_messages()) @app.route('/demo/') def demo(): return 'demo' if __name__ == '__main__': app.run()

小结:

  • get_flashed_messages()是一个列表,该列表可以取出闪现信息,该条闪现信息只要被取出就会删除掉。

在视图中实现分类获取闪现信息

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
-设置:flash('用户名错误', "username_error") flash('用户密码错误', "password_error") # 第二个参数为闪现信息的分类。 -取所有闪现信息的类别和闪现内容:get_flashed_messages(with_categories=True) -针对分类过滤取值:get_flashed_messages(category_filter=['username_error']) # 中括号内可以写多个分类。 -注意:如果flash()没有传入第二个参数进行分类,默认分类是 'message'

实例1

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
@app.route('/login/') def login(): if request.args.get('name') == 'rocky': return 'ok' flash('用户名错误', category="username_error") flash('用户密码错误', "password_error") return 'error,设置了闪现' @app.route('/get_flash/') def get_flash(): return '闪现的信息是{}'.format(get_flashed_messages(with_categories=True))

实例2

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
@app.route('/login/') def login(): if request.args.get('name') == 'rocky': return 'ok' flash('用户名错误', category="username_error") flash('用户密码错误', "password_error") return 'error,设置了闪现' @app.route('/get_flash/') def get_flash(): return '闪现的信息是{}'.format(get_flashed_messages(category_filter=['username_error']))
posted @   Franciszw  阅读(343)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开