name:启动入口
请求钩子:准备工作和收尾工作需要处理,为了让每个视图函数避免编写重复的功能
before_first_request:第一次请求前执行,适合初始化操作,比如创建文件、数据库连接
before_request:每次请求前都执行,适用对请求参数校验、统计工作(访问次数)
after_request:如果没抛出异常(服务器错误)请求后每次都执行,适合对数据交互格式做统一设置
teardown_request:每次请求后执行,记录服务器异常信息
服务器异常信息的产生:硬盘、内粗炸了,不是你代码错误
from flask import Flask
app = Flask(__name__)
@app.before_first_request
def before_first_request():
print("before_first_request")
@app.before_request
def before_request():
# 假设对请求参数做校验,不符合需求
# return ‘不符合需求’
print("before_request")
@app.after_request
def after_request(resp):
print("after_request")
resp.headers["Content-Type"] = "application/json"
return resp
@app.teardown _request
def teardown_request(e):
print(e)
print("teardown_request")
@app.route("/")
def aaaa():
return "aaa"
if __name__ == "__main__":
app.run(debug=True)
request
request:代表当前请求的request对象
需要导入requestfrom flask import Flask,request
request的属性:
data:非表单提交数据(ajax)
form:表单的post提交数据
args:get请求?后面拼接的数据
files:获取input标签type为file类型的数据
get方法取字典:字典.get(键名) :获取键值,获取不到返回None字典.get("键名","字符串") :获取键值,获取不到返回字符串
request.args是个字典
from flask import Flask,request
app = Flask(__name__)
@app.route("/")
def hello():
print(request.method)
print(request.url)
print(request.args)
# print(request.args["password"])
# 字典通过[]取值,获取不到报错,所以建议使用get
# 获取不到,返回none,也可以设置默认值
print(request.args.get("name")) # 获取不到返回none
print(request.args.get("password","xxoo") # 获取不到返回xxoo
if __name__ == "__main__":
app.run(debug=True)
http://127.0.0.1:5000?password=zhangsan&sex=man 记住这个格式
request.form的使用在数据库的案例(第33天)里面
Cookie和Session
http实无状态协议,浏览器请求服务器是无状态的,浏览器、服务器不知道之前这个用户做过什么,每次请求都是一次新的请求
无状态原因:socket套接字进行通信,服务器将请求结果返回给浏览器后,会关闭当前的socket连接
需要保持用户的浏览状态:比如是否登录,浏览过哪些商品
实现方式:
- 1.客户端存储信息使用cookie
- 2.在服务端存储使用session
cookie:由浏览器生成,存储在浏览器(键值对方式)。浏览器会将Cookie的key/vaue保存,下次请求同一网站就会发送该Cookie给服务器
cookie:复数形式Cookies
应用:网站广告推送、购物车
需要导入make_response模块和request模块from flask import Flask,make_response,request
设置方式:
response = make_response("响应体")
response.set_cookie(key,value,max_age)
max_age:过期时间,单位是秒,如果不设置默认是一次浏览器会话结束
获取方式:value = request.cookies.get(“键名”)
例:
from flask import Flask,make_response,request
app = Flask(__name__)
@app.route("/set_cookie/<username>")
def seen_computer(username):
response = make_response("正在看电脑")
response.set_cookie("product","lenovo")
response.set_cookie("username",username,10) # 10秒钟只后,username的cookie消失
return response
@app.route("/get_cookie")
def get_cookie():
product = request.cookies.get("product")
name = request.cookies.get("username")
return "name is %s,product is %s"%(name,product)
if __name__ == "__main__":
app.run(debug=True)
浏览器地址前面找cookies
session:由服务器设置,存储在服务器,用于
存储敏感信息,比如银行卡、身份证、密码信息、登录信息
需要导入sessionfrom flask import Flask,session
先设置秘钥:app.config["SECURE_KEY"] = "字符串" 如果不知道键名是什么,可以看Flask的类属性
然后设置session
设置方式:session["key"] = value
获取方式:value = session.get(key)
from flask import Flask,sesison
app = Flask(__name__)
app.config("SECURE_KEY") = 'zxcbhk'
@app.route("/set_session/<username>")
def user_login(username):
session["username"] = username
return "%s正在登录" %username
@app.route("/get_session")
def get_session():
name = session.get("username")
return "get session,name is %s"%name
if __name__ == "__main__":
app.run()
本身的内容存储在服务器里面,但是sessionID存在浏览器
sessionID是在cookie里面携带到浏览器里面
由于cookie在浏览器不安全,所有sessionID需要进行加密,加密需要秘钥
停止所有程序:ctrl+F2
不同用户登录,开辟不同的空间,生成不同的sessionID,彼此没关系的
把浏览器的cookie清掉,服务端会让你重新登录
一个浏览器不能登两个淘宝账户,因为一个用户对应一块session空间
上下文:相当于一个容器,保存了Flask程序运行过程中一些信息
共两种:请求上下文和应用上下文
请求上下文:session、request
应用上下文:current_app和g
request:封装每次相关数据,称为请求上下文
session:每个客户端请求的时候,开辟一个空间存储客户的敏感信息
应用上下文:从不同对象获取自己想要的内容,app的代理对象,用来处理用户请求,去处理request(在项目中做全局日志输出)
current_app:用于存储应用程序中的变量。app的代理(local proxy),app的所有都能使用
g:一次完整请求中有效的(在项目中封装登录器)
有多少个用户访问,创建多少个current_app和g,current_app遍历所有文件,找到用户所要的,给g
g对象:global,全局的,重定向,承着
都需要导入:from flask import Flask,current_app,g
例:
from flask import Flask,current_app,g
app = Flask(__name__)
@app.before_request
def before_request():
g.name = "zhangsan" # 请求前设置g
@app.route("/")
def hello_world():
print(app.config.get("DEBUG")) # 获取app的DEBUG对象
print(current_app.config.get("DEBUG")) # 获取current_app的DEBUG对象
# 因为current_app是app的代理,所有这两个结果一样
g.age = 13 # 收到请求后设置g
print(g.name)
print(g.age)
return "hello world"
if __name__ == "__main__":
app.run(debug=True)
Flask-Script扩展
flask-script是属于flask中的一个扩展包python 文件.py runserver -host ip地址
- 1、可以动态运行程序,指定端口,ip,调试模式等
- 2、可以配合flask_migrate做数据库迁移
使用步骤:
- 1.安装flask_script:pip install flask_script
- 2.导入flask_script的Manager类
- 3.通过Manager类管理app
- 4.运行方式:
python 文件.py runserver -h ip地址 -p 端口 -d(debug模式)
之后就只能在终端中运行,不能在pycharm里右键运行了
要想在pycharm里也能运行,进行下面设置:
在Script parameters里面填runserver变量,就可以右键和终端都运行了
例:
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
class MyConfig(object):
DEBUG = True
# 设置app类的调试模式
app.config.from_object(MyConfig) # 导入MyConfig中的配置
# 通过Manager类管理app
manager = Manager(app)
@app.route("/")
def hello_world():
return "hello_world"
if __name__ == "__main__":
manager.run()
jinja2模板:展示html界面
使用render_temple函数封装模板引擎
需要导入:from flask import Flask,render_template
render_template(“文件.html”,key=value,key2=value2),文件.html需要在templates里面
key和value的意思是把这个值带入到template的html(前面那个参数写的文件)里面
from flask import Flask,render_template
app = Flask(__name__)
@app.route("/")
def hello_world():
return render_template("file01template.html")
if __name__ == "__main__":
app.run(debug=True)
template的file01template.html里面写
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.box{
width:200px;
height:200px;
background-color:red;
}
</style>
</head>
<body>
<h2>helloworld</h2>
<div class="box"></div>
</body>
</html>
templates里面html高亮提示:右键templates文件夹–>Mark Directory as --> Template Folder,选择jinjia2
jinjia2语法
jinjia2语法:
获取变量的值:{{ }}{{ number }}
列表第一个:{{ list.0 }} {{ list[0] }}
字典名name:{{ dict.name }} {{ list[name] }}
if分支语句:
{% if 条件 %}
{% elif 条件 %}
{% else 条件 %}
{% endif 条件 %}
for循环:
{% for item in items %}
{% for item in items if item!=5 %}
{% endfor %}
如果直接是mydicct.key,那么这个key是一个字符串,如果是dict[key],那么这么key当成变量
遍历索引(写在for里面):
{{ loop.index0 }} // 从0开始索引
{{ loop.index }} // 从1开始索引
注释:{# 里面跟的是注释内容 #}
例:
from flask import Flask,render_template
app = Flask(__name__)
@app.route("/")
def hello_world():
my_number = 0
my_str = "hello"
my_tuple = (1,2,3,4,5)
my_dict = ("name":"zhangsan","age":13)
return render_template("file02program.html",
number = my_number,str=my_str,tuple=my_tuple,
list=my_list,dict=my_dict)
if __name__ == "__main__":
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>1.模板取变量</h2>
<h3>整数:{{ number }}</h3>
<h3>字符串:{{ tuple }},分开获取:{{ tuple.0 }},{{ tuple[1] }},{{ tuple.2 }}</h3>
<h3>字典:{{ dict }},分开获取:{{ dict.name }},{{ dict["age"] }}</h3>
<h2>2.遍历数组</h2>
{% for item in tuple %}
<li>{{ item }}</li>
{% endfor %}
<h2>3.获取列表偶数</h2>
{% for item in list %}
{% if item%2 ==0 %}
<h3>{{ item }}</h3>
{% endif %}
{% endfor %}
<h2>4.字典遍历</h2>
{% for key in dict %}
<h3>{{ key }}----{{ dict[key] }}</h3>
{% endfor %}
<h2>5.遍历列表索引</h2>
{% for foo in list %}
{# <h3>索引值:{{ loop.index0 }}</h3> #}
<h3>索引值:{{ loop.index }}</h3>
{% endfor %}
</body>
</html>
过滤器:1.字符串 2.列表
管道: |
例:
将hello变成大写 : <h2>{{ "hello" | upper }}</h2>
字符串过滤器:
safe:禁用转移,让html标签生效
capitalize:首字母变大写,其它变小写
lower:所有都是小写
upper:全部转大写
title:把值中所有单词的首字母都大写
reverse:字符串翻转
format:格式化输出,替换占位符
striptags:渲染之前把所有标签都删掉
<body>
<h2>字符串过滤器</h2>
{# safe:禁用转义,让html标签生效 #}
<p>{{ '<em>hello</em>' | safe }}</p>
<p>{{ "hello" | capitalize }}</p>
<p>{{ 'Hello' | lower }}</p>
<p>{{ 'hello' | upper }}</p>
<p>{{ "hello python" | title }}</p>
<p>{{ "我爱你" | reverse }}</p>
<p>{{ "%s is %d" | format('age',18) }}</p>
<p>{{ '<em>hello</em>' | striptags }}</p>
</body>
列表过滤器:
first,last,sum,length,sort
<h2>列表过滤器</h2>
{# 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] | sum }}</p>
{# sort:列表排序(升序) #}
<p>{{ [6,2,3,1,5,4] | sort }}</p>
如果系统自带满足不了需求,用自定义过滤器:
格式有两种:
1.先定义函数,后将函数添加到过滤器列表中
def 函数名称(list): # jinjia2传过来的列表,管道前面的
return "返回值" # 给jinjia2传过去的
...
app.add_template_filter(函数名称,"过滤器名称")
2.定义函数的时候,直接使用过滤器列表装饰
python文件里面写:
@app.template_filter("html里过滤器名称")
def 函数名(list): // jinjia2传过来的列表,管道前面的
return "返回值" // 给jinjia2传过去的
html里面写:{{ [列表] | 过滤器名称 }}
可以同时被两个过滤器过滤,多写个管道就OK{{ [列表] | 过滤器1 | 过滤器2 }}
from flask import Flask,render_template
app = Flask(__name__)
# 1.先定义函数,后将函数添加到过滤器列表中
def reverseList(list):
list.reverse()
return list
#参数1: 表示实现功能的函数, 参数2: 在模板中使用的过滤器名称
app.add_template_filter(reverseList,"reverseArray")
# 2.定义函数的时候,直接使用过滤器列表装饰
@app.template_filter("ouShu")
def getOuShu(list):
new_list = []
for item in list:
if item%2 == 0:
new_list.append(item)
return new_list
@app.route("/")
def hello_world():
return render_template("file04customFilter.html")
if __name__ == "__main__":
app.run(debug=True)
file04customFilter.html里面写:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>原数组:{{ [1,2,3,4,5,6] }}</h2>
<h2>反转数组:{{ [1,2,3,4,5,6] | reverseArray }}</h2>
<h2>偶数数组:{{ [1,2,3,4,5,6] | ouShu | reverseArray }}</h2>
</body>
</html>