Flask框架基础学习二
请求钩子
before_first_request
: 服务启动,第一个用户第一次访问,会调用此方法。before_request
: 请求处理之前调用after_request
: 处理请求之后调用teardown_request
: 如果有异常就触发,会传递错误异常参数(只有DEBUG=False时才会生效)
from flask import Flask
app = Flask(__name__)
class Config:
DEBUG = False
app.config.from_object(Config)
@app.before_first_request
def before_first_request():
# 服务启动,第一个用户第一次访问,会调用此方法
# 实现一些初始化操作,例如连接数据库
print("before_first_request")
@app.before_request
def before_request():
# 请求操作处理之前调用
# 基于权限对应的操作
print('before_request')
@app.after_request
def after_request(response):
# 处理请求之后调用
# 记录操作记录,清理收尾工作
print('after_request')
# 必须返回response
return response
@app.teardown_request
def teardown_request(e):
# 如果有异常触发,则会传递错误异常e
print(e)
return e
@app.route('/index')
def index():
return 'ok'
if __name__ == '__main__':
app.run()
异常捕获
-
抛出异常:
abort
- 导入:
from flask import abort
- 使用:
abort(状态码)
- 导入:
-
捕获异常
- 使用:
@app.errorhandler(状态码)
- 使用:
-
完整代码
-
from flask import Flask, abort app = Flask(__name__) class Config: DEBUG = True app.config.from_object(Config) @app.route('/index/<int:num>') def index(num): if num > 10: return 'ok' else: abort(404) # 抛出404 @app.errorhandler(404) # 捕获404这个异常 def err(e): print(e) return '<h1>错误页面</h1>' # 返回html页面或者html代码 if __name__ == '__main__': app.run()
-
context上下文
-
请求上下文
request
- 封装了HTTP请求的内容。例如:
request.args/request.form
- 封装了HTTP请求的内容。例如:
session
- 记录了请求会话中的信息。例如:
session['name']/session.get('name')
- 记录了请求会话中的信息。例如:
-
应用上下文
-
current_app
-
导入:
from flask import current_map
-
当不知道实例化flask对象名称时,可以使用
current_app
来代替flask对象名 -
from flask import Flask, current_app app = Flask(__name__) class Config: DEBUG = True app.config.from_object(Config) @app.route('/') def index(): print(app.config) print(app.url_map) # 以下输出是跟上面app.config和app.url_map输出一样的,当我们不清楚app叫什么的时候,可以使用current_app print(current_app.config) print(current_app.url_map) return 'ok' if __name__ == '__main__': app.run()
-
-
g
-
导入:
from flask import g
-
g
是flask程序全局的一个临时变量,通过它可以传递一些数据。 -
from flask import Flask, g app = Flask(__name__) class Config: DEBUG = True app.config.from_object(Config) @app.before_request def before_request(): g.name = 'aaa' # 全局范围的一个变量 @app.route('/') def index(): print(g.name) # aaa,在函数中可以调用此变量并使用 return 'ok' if __name__ == '__main__': app.run()
-
-
-
两者区别
- 请求上下文: 保存了客户端和服务器交互的数据等。
- 应用上下文: 保存了flask程序运行过程中的一些配置信息和应用信息等。
Flask-Script扩展(终端脚本工具)
-
安装:
pip install flask-script
-
使用flask-script启动flask应用
-
from flask import Flask from flask_script import Manager app = Flask(__name__) """使用flask_script启动项目""" manage = Manager(app) @app.route('/') def index(): return 'hello' if __name__ == "__main__": manager.run() # 终端命令 python run.py runserver # 不写域名和端口,默认是127.0.0.1和5000 # 通过-h设置启动域名,-p设置启动端口 python run.py runserver -h127.0.0.1 -p5000
-
-
自定义脚本命令
-
# main.py import os from flask import Flask from flask_script import Manager, Command, Option app = Flask(__name__) class Config: DEBUG = True app.config.from_object(Config) manager = Manager(app) class BluePrinter(Command): option_list = [ Option('--filename', '-f', help="提示"), # 自定义命令: 参数一是全称,参数二是简称 Option('--name', '-n', help="提示") # 可以指定多个参数 ] def run(self, filename=None, name=None): # 这边的形参必须和上述参数一致 if filename is None: return if not os.path.exists(filename): # 没有文件夹的情况下 os.mkdir(filename) open(f'{filename}/views.py', 'w', encoding='utf-8') open(f'{filename}/models.py', 'w', encoding='utf-8') with open(f"{filename}/urls.py","w", encoding='utf-8') as fp: fp.write("""from . import views urlpatterns = [ ] """) manager.add_command('blue', BluePrinter) # 定义命令名称 if __name__ == '__main__': manager.run() # 执行(python 文件名 命令名 指令命令=参数) # python main.py blue --filename=users # python main.py blue -f=users
-
jinja2模板引擎
基本使用
- 视图函数传参:
render_template("index.html", name=name, info=info)
- 模板接收参数:
<p>{{ name }} {{ info }}</p>
视图代码
# main.py
from flask import Flask, render_template
app = Flask(__name__)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@app.route('/')
def index():
name = 'bbb'
hobby = ['game', 'music', 'book']
info = {
'age': 24,
'sex': True
}
p = Person('aaa', 24)
data = [
{"id": 1, "price": 78.50, "title": "书本1"},
{"id": 5, "price": 88.50, "title": "书本2"},
{"id": 3, "price": 98.50, "title": "书本3"},
{"id": 2, "price": 71.50, "title": "书本4"},
{"id": 7, "price": 63.50, "title": "书本5"},
{"id": 6, "price": 58.50, "title": "书本6"},
]
dic = {
'name': name,
'hobby': hobby,
'info': info,
'person': p,
'data': data
}
return render_template('index.html', **dic)
if __name__ == '__main__':
app.run()
模板代码
# 模板代码
<div>
{{ name }} <!-- bbb -->
{{ hobby[0] }} <!-- game -->
{{ info.age }} <!-- 24 -->
{{ person.age }} <!-- 24 -->
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>ID</th>
<th>价格</th>
<th>名称</th>
</tr>
</thead>
<tbody>
{% for i in data %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ i.id }}</td>
{% if i.price > 70 %}
<td>{{ i.price }},还是太贵了</td>
{% else %}
<td>{{ i.price }},价格比较便宜</td>
{% endif %}
<td>{{ i.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!--
序号 ID 价格 名称
1 1 78.5,还是太贵了 书本1
2 5 88.5,还是太贵了 书本2
3 3 98.5,还是太贵了 书本3
4 2 71.5,还是太贵了 书本4
5 7 63.5,价格比较便宜 书本5
6 6 58.5,价格比较便宜 书本6
-->
{{ request.method }} <!-- GET -->
{{ session }} <!-- session对象 -->
{{ url_for('index') }} <!-- /(index视图函数对应的URL) -->
</div>
- for循环中的一些特殊变量
变量 | 描述 |
---|---|
loop.index | 循环的次数(从1开始) |
loop.index0 | 循环的次数(从0开始) |
loop.revindex | 到循环结束还差几次(从0开始) |
loop.revindex0 | 到循环结束还差几次(从1开始) |
loop.first | 当此次是第一次循环,则为True,反之则为False |
loop.last | 当此次是最后一次循环,则为True,反之则为False |
loop.length | 循环序列的长度 |
过滤器
字符串操作
指令 | 解释 |
---|---|
safe | 转义 |
capitalize | 首字母大写,其他小写 |
lower | 字符串全部小写 |
upper | 全部大写 |
title | 值中的每个单词的首字母都转成大写 |
reverse | 字符串反转 |
format | ‘%s in %s’ | format(“a”, “aaa”) 格式化输出 |
striptags | 渲染之前将html标签都删除(遇到>或<在内容中会有歧义) |
truncate | 字符串截断 |
列表操作
指令 | 解释 |
---|---|
first | 取列表的第一个元素 |
last | 取列表的最后一个元素 |
length | 获取列表的长度 |
sum | 求列表的总和 |
sort | 列表排序(从小到大) |
语句块
{% filter upper %}
aaaaa
bbbbb
ccccc
{% endfilter %}
"""
结果:
AAAAA
BBBBB
CCCCC
"""
自定义过滤器
# 需求: 将列表反转再拼接成字符串
# 方式一
def reverse(old):
new_list = list(old)
new_list.reverse()
new_string = ''.join(new_list)
return new_string
app.add_template_filter(reverse, 'rev_join') # 这里添加
# 方式二
@app.template_filter('rev_join') # 这里添加
def reverse(old):
new_list = list(old)
new_list.reverse()
new_string = ''.join(new_list)
return new_string
# 使用: {{ ["a", "b", 'c', 'd'] | rev_join }} --> dcba
# 案例: 将手机号只保留前三位和后四位 13222999000 --> 132****9000
@app.template_filter('hide_phone') # 这里添加
def reverse(phone, hide_string):
p_str = phone[:3] + hide_string + phone[-4:]
return p_str
# 使用: {{ "13222929986" | hide_phone("****") }} --> 132****9986
模板继承
base.html
{# 创建一个base.html作为模板 #}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="{{ url_for('static',filename='./css/style.css') }}">
{# 创建一个static文件夹用来放静态文件,filename指向的静态文件就是从这个static开始往下 #}
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="head">
<h1>头部</h1>
</div>
{% block main %} {# 声明一个块 #}
<div id="main">
<h4>这是base页面</h4>
</div>
{% endblock %}
<div id="footer">
<h4>底部</h4>
</div>
</body>
</html>
index.html
{% extends "base.html" %} {# 继承模板 #}
{% block main %}
{{ super() }} {# 当使用super时,可以将模板中这一块的代码也显示出来 #}
<div id="main">
<h4>这是index页面</h4>
</div>
{% endblock %}
当用户查看index页面时,输出下面代码
<body> <div id="head"> <h1>头部</h1> </div> <!-- 当使用super的时候这里注释的代码也会显示出来,因为它是模板中这一块的代码 <div id="main"> <h4>这是base页面</h4> </div> --> <div id="main"> <h4>这是index页面</h4> </div> <div id="footer"> <h4>底部</h4> </div> </body>