本系列的内容来自读书笔记:《Flask Web 开发 :基于 Python 的 Web 应用开发实战》
一. flask入门
WEB工作原理
-
C/S和B/S架构
-
B/S架构的工作原理
客户端(浏览器)《=》WEB服务器(Apache,nginx)《=》WSGI《=》Python(flask)
二. Flask框架
(1) 简介
flask是一个非常小的python web框架, 被称为微型框架, 只提供了一个强健的核心, 其他的功能都是通过扩展来实现的, 所以会使用很多的扩展模块
(2) 组成
1. 调试, 路由, wsgi
2. 模板引擎
3. 安装
pip install flask
4. 路由的配置
@app.route('/') # app可以随意起名字
def index():
# 视图函数
pass
5. 完整代码
from flask import Flask # 导入flask
# 创建flask实例
app = Flask(__name__)
# 配置路由
@app.route('/')
def index():
return '我是首页'
if __name__ == '__main__':
app.run()
然后浏览器输入http://127.0.0.1:5000
6. 启动参数run(debug, port, host, threaded)
参数 | 说明 |
---|---|
debug | 是否开启调试模式(True/False), 默认为False, 如果开启会自动加载代码 |
port | 指定端口号 |
host | 指定主机名 设置为0.0.0.0 |
threaded | 是否开启多线程, 默认False |
实例:
app.run(debug=True,port=5050,threaded=True,host='0.0.0.0')
7.请求和响应
变量和对象 | 说明 |
---|---|
current_app | 当前运行应用的实例 |
g | 处理请求的临时变量, 每次请求都会重置 |
request | 请求对象, 保存客户端的所有HTTP请求的信息 |
session | 会话控制 用于存储会话信息 |
app对象:
全局应用对象
作用: 公共的全局配置, 可以加在这个对象上
实例:
# 给全局对象添加一个属性
app.good = 'goods'
current_app
在任何的视图中, 可以使用current_app访问到全局的app对象
作用: 因为公共的配置都写在了app对象上, 所以可以在所有的视图函数中, 通过current_app访问全局对象app
from flask import current_app
@app.route('/globalapp/')
def globalapp():
return '%s 获取全局good属性值, 通过current_app' % current_app.good
request
作用: 获取请求报文中的数据
概述:
- 浏览器发送到服务器中的所有报文被flask接收后, 创建request对象, request对象被用在视图函数中, 获取请求的数据
- request对象由flask创建好以后, 引入就可以使用
- 导入
from flask import request
属性:
-
url : 完整请求url
-
base_url: 去掉GET参数的url
-
host_url: 只有主机ip和端口号
-
path: 路由地址
-
method: 请求方式
-
remote_addr: 客户端的ip地址
-
args: 获取GET请求的参数
print(request.args['name']) # 获取参数 print(request.args.get(['age'])) # 获取参数,获取不到返回None
-
form: 存储表单的数据
-
files: 用于文件上传
-
headers: 获取所有的请求头信息
-
cookies: 获取cookie
获取GET参数:
# http://127.0.0.1:5000/?a=xxx&a=18
print(request.args.get('a',)) # xxx 存在相同的返回第一个
print(request.args.getlist('a',)) # 获取同名的多个参数, 返回列表
三. 路由设置
(1) 无参路由
实例:
@app.route('/test/')
def test():
return '测试无参路由'
@app.route('/tt/')
@app.route('/tt1/')
@app.route('/tt2/') # 可以同时添加多个路由
def t():
return '测试无参路由'
注意: 路由的地址, 可以和视图函数的名称不一致
(2) 有参路由
实例:
@app.route('/welcome/<name>') # 一个参数的路由
def welcome(name):
return '欢迎 %s' % name
# 浏览器输入http://127.0.0.1/welcome/张三
# 多个参数的路由
@app.route('/test/<a>/<b>')
def t(a, b):
print(a, b)
return '多个参数'
(3) 路由参数的限定
实例:
@app.route('/welcome2/<int:arg>') # 只能匹配到整形 http://127.0.0.1/welcome/10
@app.route('/welcome2/<float:arg>') # 只能匹配到浮点型 http://127.0.0.1/welcome/10.1
@app.route('/welcome2/<string:arg>') # 默认, 接受任何不带斜线的字符串
@app.route('/welcome2/<path:arg>') # 和string相似,但也接受斜线
注意:
- 路由末尾的
/
建议都加上, 因为在路由需要/
时浏览器会自动帮你加上, 也就是说输入的时候/
可加可不加 - 若需要指定参数 将参数名称写在
<>
中, 视图(函数)的参数和路由的参数<u>名称</u>保持一致 - 若要限定参数的类型在
<int/float/string/path:参数名称>
- 不指定类型默认为string类型, 如果使用path的话
/
不在是路由的分隔符, 而是代表路径
四. 路由的响应(response)
(1) 响应状态码404(但是请求成功)
实例:
@app.route('/res/')
def res():
return 'Page not Found ', 404 # 改变返回的状态码值,其实是请求成功的
(2) 通过make_response来构造响应对象
导入: from flask import make_response
实例:
@app.route('/res/')
def res():
respon = make_response('Page not found') # 200 单纯的响应结果
respon = make_response('Page not found', 404) # 响应结果 改变http状态码
return respon
五. 重定向(redirect)
作用: 可以在视图直接去跳转
导入: from flask import redirect,url_for
实例:
@app.route('/r_redirect/')
def r_redirect():
return redirect('/test/', ) # 重定向, 参数为路由名称
return url_for('t') # 通过视图函数 反向构造出路由
print(url_for('t', a=1, b=2)) # /test/1/2 ,其中参数名a和b与视图函数对应
return url_for('t', a=1, b=2) # 通过视图函数 反向构造出路由和参数(关键字为参数名)
return redirect(url_for('welcome2',arg=101)) # 重定向
六.abort(终止)
- 如果在视图处理中, 如果出现了异常错误, 可以使用abort函数立即终止视图函数的执行
- 如果abort函数被触发, 后面的代码和程序就不在执行, 类似python的raise
- 通过abort函数可以向前端(浏览器端)返回一个HTTP标准中的状态码, 表示出现错误的信息, 如果向浏览器返回一个不存在的Http状态码是没有任何意义的
示例:
@app.route('/')
def index():
abort(404) # 抛出404的异常
print("aa") # 下面不在执行
return '我是首页'
错误页面的定制:
@app.errorhandler(404) # 括号中添加捕获状态码的值, 捕获404错误
def page_not_found(e): # 必须传一个参数
print(e)
return e # e代表当前状态码对应的信息 正常会调用模板去显示对应状态码的页面
七. 会话控制(cookie和session)
(1) cookie
参数:
Response.set_cookie(
key,
value='',
max_age=None, # 以秒为单位的cookie寿命
expires=None, # 失效时间 datetime对象或者为Unix时间戳
path='/' # cookie的有效路径
)
设置cookie实例:
@app.route('/set_cookie/')
def setCookie():
response = make_response('设置cookie')
# Response.set_cookie('name', 'zs') # 设置cookie
exp = time.time()+20 # 时间戳
response.set_cookie('name', 'zs', expires=exp) # 设置cookie过期时间
response.set_cookie('name', 'zs', max_age=3600) # 设置cookie一小时的过期时间
return Response
获取cookie的实例:
@app.route('/get_cookie/')
def getCookie():
# 如果没有响应给浏览器会报错, 所有要有默认值
return request.cookies.get('name', '默认值') # 获取cookie的实例
return request.cookies.get('nameaa') # 如果获取不到会报错
return request.cookies.get('nameaa') or 'default' # 获取cookie的实例
删除cookie的实例:
@app.route('/del_cookie/')
def delCookie():
response = make_response('删除cookie')
response.delete_cookie('name')
return Response
(2) session
session基于cookie, session会将唯一标识符session-id存储于cookie中, 每次请求cookie会带着唯一的id去访问, 服务器端会根据唯一的id来区分每一个用户
1. 设置session
Flask对象会将会话储存在客户端的cookie中, 因此需要为应用实例的属性secret_key配置加密种子session, 才可以使用
**导入session **
from flask import session
设置密钥(加密字符串)
app.secret_key = '123456' # 设置secret_key
app.config['SECRET_KEY'] = '123456' # 法二, 大写, 推荐使用
设置session:
@app.route('/set_session/')
def setSesstion():
session['age'] = 18 # 默认存活时间为浏览器会话结束时
return '设置session'
设置session带过期时间
导入模块:from datetime import timedelta
timedelta
为datetime
的一个对象, 该对象表示俩个时间的差值
构造函数:
datetime.timedelta(days=0,minutes=0,seconds=0,weeks=0,hours=0)
实例:
@app.route('/set_session/')
def setSesstion():
from datetime import timedelta
session.permanent=True # 设置session开启持久化
app.permanent_session_lifetime = timedelta(minutes=5) # 设置存活时间为5分钟
session['age'] = 18
return '设置session'
2. 获取session
@app.route('/get_session/')
def get_Session():
return str(session.get('age', 'default')) # 返回int不能响应,所以强转成str
3. 删除session
@app.route("/del_session/")
def del_session():
session.pop('age','default') # 删除key为age的session
session.clear() # 删除当前session的所有数据(一个session可能包含name,age等)
return '删除session'
八. flask-script
概念: 就是一个flask终端运行的解析器 因为项目测试完不需要更改任何的代码, 否则有可能会带风险, 所以要借助这个库通过更改命令完成不同的启动
(2) 安装:pip install flask-script
(3) 使用
from flask-script import Manager
app = Flask(__name__)
manage = Manager(app) # 实例化Manager
if __name__ == '__main__':
# app.run(debug=True)
manage.run() # 新添加的
(4) 启动参数
-?,--help # 请求帮助
-h,--HOST # 设置主机名
-p,--PORT # 设置端口号
--threaded # 启用多线程
-d # 开启调试模式
-r # 开启自动加载
实例:
python 文件名.py runserver -h 0.0.0.0 -p 5000 -d -r
python 文件名.py runserver -h 0.0.0.0 -p 5000 -d -r --threaded
九. 蓝本(Blueprint)
概念: 当代码越来越多比较复杂的时候, 可以通过蓝本将对应功能的视图独立出来
步骤:
-
新建一个文件
user.py
from flask import Blueprint #创建蓝本对象 user = Blueprint('user',__name__) # 第一个参数可看做该blueprint对象的姓名,姓名不能与其余的Blueprint对象姓名重复,第二个参数__name__用作初始化 @user.route('/login/') def login(): return '登录' @user.route('/loguut/') def logout(): return '退出登录'
-
在主文件下添加如下代码
from user import user # app.register_blueprint(user) # 注册蓝本 app.register_blueprint(user,url_prefix='/user') # 访问前缀, 访问的时候需要/user/login/
拓展:
(1) 蓝本和manage直接的跳转和参数的传递
manage.py文件
app = Flask(__name__)
manage = Manager(app)
@app.route('/')
def index():
return redirect(url_for('abcd.login'))
return redirect(url_for('abcd.login',a=1,b=2)) # 带参数的蓝本跳转
from user import user
app.register_blueprint(user) # 注册蓝本
user.py文件
user = Blueprint("abcd", __name__) # 第一个参数 根据名字 找视图abcd.login
@user.route('/login/<a>/<b>') # 带参数的蓝本
def login(a, b):
print(a, b) # 1 2 http://127.0.0.1/login/1/2
return '登录'
注意:
- 如果url_for()第二个参数传递的关键字参数(例如:name)名, 在反向构造函数(url_for调用的函数)中不存在则为
aa/?name=xx
, 如果存在则为aa/name/
(2) 蓝本带前缀路由之间的跳转,manage->user user->manage
manage.py文件
@app.route('/test/')
def test():
# 如果添加一个login不存在的关键字a, 则地址为http://127.0.0.1/login/zs/?a=xx
return redirect(url_for('user.login', name='zs'))
app.register_blueprint(user, url_prefix='/user') # 注册蓝本,带访问前缀
user.py文件中
@user.route('/login/<name>')
def login(name):
print(name) # http://127.0.0.1/login/zs
return '登录'
九. 请求钩子函数
概念: 类似于django的中间件, 写在蓝图中, 只针对蓝图的请求, 在蓝图中需要对应使用钩子函数
钩子函数 | 功能描述 |
---|---|
before_app_first_request | 第一次请求之前 |
before_app_request | 每次请求之前 |
after_app_request | 每次请求之后(前提没有异常) |
teardown_app_request | 每次请求之后 |
实例:
@user.route('/login/')
def login():
return '登录'
@user.before_app_first_request
def beforeAppFR():
print('before_app_first_request')
@user.before_app_request
def beforeApp():
#可以如下这样使用
if request.path == '/login/' and request.method="GET": #当请求login视图的时候 如果为 get请求 则请求失败 只是添加一个过滤 确保数据传输和请求更加安全
abort(404)
print('before_app_request')
@user.after_app_request
def afterApp(response):
print(response)
print('after_app_request')
return response
@user.teardown_app_request
def teardown(exception):
print(exception)
print('teardown_app_request')
网友评论