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()