Request对象
- Flask中的request对象是通过导入使用的,而不是通过视图函数传参的方式
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
print(request.method) # GET
return 'login'
if __name__ == '__main__':
app.run()
- request对象下的相关属性(即: 请求相关的信息)
request.method
request.args
request.json
request.form
request.values
request.cookies
request.headers
request.path
request.full_path
request.script_root
request.url
request.base_url
request.url_root
request.host_url
request.host
request.files
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename))
响应体相关的操作
1. 直接返回字符串或数字
- 相当于 Django 中的 HttpResponse
- 将字符串或数字发送给浏览器
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
return 'login'
if __name__ == '__main__':
app.run()
2. render_template
- 相当于 Django 中的 render
- 将指定的HTML文件内容发送给浏览器
# app.py
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run()
- 将指定的数据传递给HTML模板
- 写法一
# app.py
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
return render_template('login.html', data1='数据一', data2='数据二')
if __name__ == '__main__':
app.run()
- 写法二
# app.py
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
return render_template('login.html', **{'data1': '数据一', 'data2': '数据二'})
if __name__ == '__main__':
app.run()
3. redirect
- 相当于 Django 中的 redirect
- 网页重定向
# app.py
from flask import Flask, request, redirect
app = Flask(__name__)
@app.route('/baidu', methods=['GET', 'POST'])
def login():
return redirect('/index') # 跳转到 index 页面
@app.route('/index')
def index():
return redirect('https://www.baidu.com/') # 跳转到百度
if __name__ == '__main__':
app.run()
4. jsonify
- jsonify 和 Django 中的 JsonResponse 类似
- jsonify 的作用生成一个Json格式的字符串,而不需要使用 json 模块去生成Json格式的字符串,直接使用 jsonify 就可以了
- jsonify 可以直接序列化所有 json 支持的数据格式
# app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/index')
def index():
dic = {'name': 'Kevin', 'age': 22}
arr = [1, 2, 3]
s = '字符串'
n = 10
b = True
# return jsonify(dic)
# return jsonify(arr)
# return jsonify(s)
# return jsonify(n)
return jsonify(b)
if __name__ == '__main__':
app.run()
CBV 与 FBV
1. CBV -> class base views
- CBV的本质还是FBV
- 基于类编写的视图
# app.py
from flask import Flask, views
app = Flask(__name__)
class IndexView(views.MethodView):
methods = ['GET', 'POST'] # 允许xxx请求访问当前路由,默认 GET 请求
def get(self, *args, **kwargs):
return 'index_get'
def post(self, *args, **kwargs):
return 'post_get'
app.add_url_rule(rule='/index', endpoint=None, view_func=IndexView.as_view('index')) # .as_view() 方法必须接收一个名字,且这个名字就代表着 .as_view() 所返回的函数的函数名(即: 该名字类似于视图函数的函数名)
if __name__ == '__main__':
app.run()
- CBV接收url的参数
# app.py
from flask import Flask, views
app = Flask(__name__)
class IndexView(views.MethodView):
methods = ['GET', 'POST']
def get(self, uid, pid):
print(uid, pid) # 3 2
return 'index_get'
def post(self, uid, pid):
print(uid, pid) # 3 2
return 'post_get'
app.add_url_rule(rule='/index/<int:uid>/<int:pid>', endpoint=None, view_func=IndexView.as_view('index'))
if __name__ == '__main__':
app.run()
- dispatch_request方法
- dispatch_request方法 和 Django 中 CBV 的 dispatch 方法类似
- dispatch_request方法其实是CBV源码中用于根据不同的请求方式调用不同的方法(即: 如果是GET请求,那么就会执行你所创建的CBV中的处理get请求的方法)
- 在执行CBV中处理请求的方法(即: 你所创建的CBV中的处理get/post请求的方法)之前都会先执行一次 dispatch_request 方法,因为dispatch_request方法的作用就是根据不同的请求方式调用不同的方法(即: 如果是GET请求,那么就会执行你所创建的CBV中的处理get请求的方法)
- 注意: 如果在CBV中使用dispatch_request方法,那么一定要返回调用父类View中的dispatch_request方法的返回值,除非自己实现请求方法的分发功能(即: 如果是GET请求,那么就会执行你所创建的CBV中的处理get请求的方法)
- 使用场景:
- CBV处理请求的方法(即: 你所创建的CBV中的处理get/post请求的方法)中出现相同的操作时,可以将该相同的操作放到 dispatch_request 方法中执行
# app.py
from flask import Flask, views
app = Flask(__name__)
class IndexView(views.MethodView):
methods = ['GET', 'POST']
def dispatch_request(self, *args, **kwargs):
print('执行 get方法 和 post方法 都有的操作')
return super(IndexView, self).dispatch_request(*args, **kwargs) # 调用父类MethodView的dispatch_request方法,根据不同的请求方式调用不同方法(即: 如果是GET请求,那么就会执行下方get方法)
# 一定要返回调用父类MethodView的dispatch_request方法的返回值
def get(self, *args, **kwargs):
return 'index_get'
def post(self, *args, **kwargs):
return 'post_get'
app.add_url_rule(rule='/index', endpoint=None, view_func=IndexView.as_view('index'))
if __name__ == '__main__':
app.run()
- 自己实现请求方法的分发功能(即: 如果是GET请求,那么就会执行你所创建的CBV中的处理get请求的方法),类似于中间件的功能
# app.py
from flask import Flask, views, request
app = Flask(__name__)
class IndexView(views.MethodView):
methods = ['GET', 'POST']
def dispatch_request(self, *args, **kwargs):
if request.method == 'GET':
return self.get()
else:
return self.post()
def get(self, *args, **kwargs):
return 'index_get'
def post(self, *args, **kwargs):
return 'post_get'
app.add_url_rule(rule='/index', endpoint=None, view_func=IndexView.as_view('index'))
if __name__ == '__main__':
app.run()
- 注意事项:
- 使用 CBV 时一定要使用 app.add_url_rule() 添加路有关系
- view_func 参数所接收的值一定要是函数(即: 视图类一定要调用 .as_view() 方法返回一个函数给 view_func 参数)
- .as_view() 方法必须接收一个名字,且这个名字就代表着 .as_view() 所返回的函数的函数名(即: 该名字类似于视图函数的函数名)
app.add_url_rule(rule='/index', endpoint=None, view_func=IndexView.as_view('index')) # .as_view() 方法必须接收一个名字,且这个名字就代表着 .as_view() 所返回的函数的函数名(即: 该名字类似于视图函数的函数名)
2.FBV -> function base views
- 基于函数编写的视图
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/index', methods=['GET', 'POST'])
def index():
return 'index'
if __name__ == '__main__':
app.run()
获取请求的数据
1. request.method -> 获取使用了什么请求方式
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
print(request.method) # GET
return 'login'
if __name__ == '__main__':
app.run()
2. request.args -> 获取 GET 请求的数据
- 通常我们访问一个网址就是使用了 GET 请求
- 获取 GET 请求的数据 -> request.args
- request.args -> 返回值: ImmutableMultiDict([('name', 'Kevin'), ……]),如果没有值会返回一个空字典:ImmutableMultiDict([]) -> 类似于一个字典
- 注意: 从 request.args中获取到的值都是字符串类型的
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
get_data = request.args
print(get_data) # ImmutableMultiDict([('name', 'Kevin'), ('password', '123')]) -> ImmutableMultiDict 本质上就是一个字典
# 使用 .get() 方法获取 GET 请求中指定的数据,防止没有该值而报错,因为 request.args 的返回值是字典,所以可以使用 .get() 方法,如果不懂可以看会字典中的 .get() 方法
print(get_data.get('name')) # Kevin
print(get_data.get('password')) # 123
return 'login'
if __name__ == '__main__':
app.run()
3. request.form-> 获取 POST 请求的数据
- 获取 POST 请求的数据 -> request.form
- request.form 只能获取 contentType=application/x-www-form-urlencoded 发送过来的数据,不能获取 contentType=application/json 发送过来的数据
- request.form 什么时候有值:
- 以 application/x-www-form-urlencoded 编码格式发送过来的数据,那么 request.form 中是有值的
- 以 application/json 编码格式发送过来的数据,那么 request.form 中是没有值的,只能在 request.json 中获取
- request.form -> 返回值: ImmutableMultiDict([('name', 'Kevin'), ……]),如果没有值会返回一个空字典:ImmutableMultiDict([]) -> 类似于一个字典
- 注意: 从 request.form 中获取到的值都是字符串类型的
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
post_data = request.form
print(post_data) # ImmutableMultiDict([('name', 'Kevin'), ('password', '123')]) -> ImmutableMultiDict 本质上就是一个字典
# 使用 .get() 方法获取 POST 请求中指定的数据,防止没有该值而报错,因为 request.form 的返回值是字典,所以可以使用 .get() 方法,如果不懂可以看会字典中的 .get() 方法
print(post_data.get('name')) # Kevin
print(post_data.get('password')) # 123
return 'login'
if __name__ == '__main__':
app.run()
4. request.json-> 获取 POST 请求的数据
- 获取 POST 请求的数据 -> request.json
- request.json 只能获取 contentType=application/json 发送过来的数据
- request.json -> 返回值: 字典 {'name': 'Kevin', 'password': '123'},如果没有值会返回一个空字典 或 None
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
json_data = request.json
print(json_data) # {'name': 'Kevin', 'password': '123'}
# 使用 .get() 方法获取 POST 请求中指定的数据,防止没有该值而报错,因为 request.json 的返回值是字典,所以可以使用 .get() 方法,如果不懂可以看会字典中的 .get() 方法
print(json_data.get('name')) # Kevin
print(json_data.get('password')) # 123
return 'login'
if __name__ == '__main__':
app.run()
make_response 响应
- make_response 一般用于设置 cookie、响应头 或 状态码
- response 是 flask.wrappers.Response 类型
1. 设置响应头
# app.py
from flask import Flask, render_template, jsonify, make_response
app = Flask(__name__)
@app.route('/index')
def index():
# response = make_response('index') # 创建响应对象 -> 返回的类型是字符串或数字
# response = make_response(render_template('index.html')) # 创建响应对象 -> 返回的类型是页面
response = make_response(jsonify({'name': 'Kevin', 'age': 22})) # 创建响应对象 -> 返回的类型是JSON字符串
response.headers['header_key'] = '123' # 设置响应头
return response
if __name__ == '__main__':
app.run()

2. 设置 cookie
# app.py
from flask import Flask, render_template, make_response
app = Flask(__name__)
@app.route('/index')
def index():
response = make_response(render_template('index.html'))
response.set_cookie('c_key', 'c_value') # 设置 cookie
return response
if __name__ == '__main__':
app.run()
3. 删除 cookie
# app.py
from flask import Flask, render_template, make_response
app = Flask(__name__)
@app.route('/index')
def index():
response = make_response(render_template('index.html'))
response.delete_cookie('c_key') # 删除 cookie
return response
if __name__ == '__main__':
app.run()
4. 设置状态码
- 写法一
- 在make_response()中传入状态码
# app.py
from flask import Flask, render_template, make_response
app = Flask(__name__)
@app.route('/index')
def index():
response = make_response(render_template('index.html'), 400)
return response
if __name__ == '__main__':
app.run()
- 写法二
- 直接return状态码
# app.py
from flask import Flask, render_template, make_response
app = Flask(__name__)
@app.route('/index')
def index():
response = make_response(render_template('index.html'))
return response, 400
if __name__ == '__main__':
app.run()
给视图添加装饰器
1.使用装饰器装饰 FBV
- 注意事项:
- 自己编写的装饰器一定要使用 wraps 装饰器修复技术
- 说明: 因为当函数使用了装饰器,那么该函数的信息默认就会指向装饰器中的 inner 函数,当在 Flask 中使用自己编写的装饰器的时候,路由中的 endpoint 参数的值就会等于装饰器中 inner 函数名,当多个视图函数使用了同一个装饰器的时候就会报错,因为 endpoint 参数的值不能重复(即: 视图函数名不能重复)
- 报错信息:
- 装饰器一定要写在路由装饰器的下面
# app.py
import time
from flask import Flask, render_template
from functools import wraps
app = Flask(__name__)
def time_wrapper(fn):
@wraps(fn)
def inner(*args, **kwargs):
start_time = time.time()
ret = fn(*args, **kwargs)
end_time = time.time()
print("used:", end_time - start_time)
return ret
return inner
@app.route('/index')
@time_wrapper
def index():
return render_template('index.html')
@app.route('/login')
@time_wrapper
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run()
2.使用装饰器装饰 CBV
- 批量添加装饰器(即: 视图类下的视图方法都会装饰上指定的某几个装饰器)
# app.py
from flask import Flask, views
from functools import wraps
app = Flask(__name__)
def wrapper(fn):
@wraps(fn)
def inner(*args, **kwargs):
print('前')
ret = fn(*args, **kwargs)
print('后')
return ret
return inner
class IndexView(views.MethodView):
methods = ['GET', 'POST']
decorators = [wrapper] # 批量添加装饰器(即: 给每一个视图方法添加装饰器)
def get(self, *args, **kwargs):
return 'index_get'
def post(self, *args, **kwargs):
return 'post_get'
app.add_url_rule(rule='/index', endpoint=None, view_func=IndexView.as_view('index'))
if __name__ == '__main__':
app.run()
- 局部添加装饰器(即: 给指定的某一个视图方法添加装饰器)
# app.py
from flask import Flask, views
from functools import wraps
app = Flask(__name__)
def wrapper(fn):
@wraps(fn)
def inner(*args, **kwargs):
print('前')
ret = fn(*args, **kwargs)
print('后')
return ret
return inner
class IndexView(views.MethodView):
methods = ['GET', 'POST']
@wrapper
def get(self, *args, **kwargs):
return 'index_get'
def post(self, *args, **kwargs):
return 'post_get'
app.add_url_rule(rule='/index', endpoint=None, view_func=IndexView.as_view('index'))
if __name__ == '__main__':
app.run()
其他
1. mark_safe -> 不对html标签进行转义
- Markup 相当于 Django 中的 mark_safe
# app.py
from flask import Flask, render_template, Markup
app = Flask(__name__)
@app.route('/index')
def index():
a = Markup('<a href="https://www.baidu.com">百度</a>')
return render_template('index.html', a=a)
if __name__ == '__main__':
app.run()