路由系统

有名分组

from flask import Flask
app=Flask(__name__)

@app.route('/<int:nid>',strict_slashes=False)
def index(nid):
    print(nid)
    return 'ok'

#对URL最后的 / 符号是否严格要求
strict_slashes = None
    '''
        @app.route('/index', strict_slashes=False) 非严格模式
        #访问http://www.xx.com/index/ 或http://www.xx.com/index均可
        @app.route('/index', strict_slashes=True) 严格模式
        #仅访问http://www.xx.com/index
    '''
#重定向到指定地址
redirect_to = None,
    '''
        @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
    '''

CBV

from flask import Flask,views
app=Flask(__name__)

class IndexView(view.View):
    methods=['GET']
    def dispatch_request(self):
        print('index')
        return 'index123'

app.add_url_rule('/index1,view_func=IndexView.as_view(name='index')') # 优先找endpoint=''名字,没有找as_view中name

if __name__='__main__':
    app.run()

重写dispatch分发

  class IndexView(views.MethodView):
            methods = ['GET']
            #cbv添加装饰,用这个,我们看as_view中就知道了
            decorators = [auth, ]

            def get(self):
                return 'Index.GET'

            def post(self):
                return 'Index.POST'
#如果我们继承了MethodView,他帮我们重写了,dispatch_request方法,他给我们做了一个分发,通过请求,来执行不同的函数
app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint

正则

# 1.写类:继承BaseConverter
# 2.注册:app.url_map.converters['regex'] = RegexConverter
# 3.使用:@app.route('/index/<regex('\d+'):nid>') 正则表达式会当作第二个参数传递到类中
from flask import Flask, views, url_for
from werzeug.routing import BaseConverter

app = Flask(import_name=__name__)

class RegexConverter(BaseConverter):
    """
    自定义URL匹配正则表达式
    """
    def __init__(self, map, regex):
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        """
        return int(value)

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        """
        val = super(RegexConverter, self).to_url(value)
        return val
# 添加到flask中
app.url.map.converters['regex'] = RegexConverter
@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'

if __name__ = '__main__':
    app.run()

模板

前端页面渲染变量

'''
模板里面
渲染变量
{{}}-->和django一样
{% for k,v in dict.item()%}
    {{v.name}}
    {{v.get("name")}}
    {{v['name']}}
{% endfor %}
'''
# <a>{{url_for("l1")}}</a> --> '/login',前端页面反向解析视图函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>用户列表</h1>
    <table>
        {% for k,v in user_dict.items() %}
        <tr>
            <td>{{k}}</td>
            <td>{{v.name}}</td>
            <td>{{v['name']}}</td>
            <td>{{v.get('name')}}</td>
            <td><a href="/detail/{{k}}">查看详细</a></td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

后端

'''
methods=["GET","POST]
/detail/<int:nid>
nid会当做参数传给我们的视图函数
我们给模板传值的必须是关键字传值
url_for()做反向解析,填的是endpoint的值,如果要跳转的视图没有指定endpoint,就用函数名

'''

USERS = {
    1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
    2:{'name':'李四','age':28,'gender':'男','text':"安全第一条"},
    3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}

@app.route('/detail/<int:nid>',methods=['GET'])
def detail(nid):

    info = USERS.get(nid)
    return render_template('detail.html',info=info)


@app.route('/index',methods=['GET'])
def index():
    # return redirect('/login')
    url = url_for('l1')
    return redirect(url)
    #return render_template('index.html',user_dict=USERS)


@app.route('/login',methods=['GET','POST'],endpoint='l1')
def login():
    if request.method == "GET":
        return render_template('login.html')
    else:
        # request.query_string
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        if user == 'cxw' and pwd == '123':

            return redirect('http://www.baidu.com')
        return render_template('login.html',error='用户名或密码错误')

# flask中Markup(<h1>哇!</h1>)等价django中的mark_safe('<h1>哇!</h1>'),防止前端页面xss攻击{{  | safe}}
def func1(a,b):
    # return (f"<h1>蔡徐坤{a},{b}</h1>")
    return Markup(f"<h1>蔡徐坤{a},{b}</h1>")



@app.route("/test")
def py_test():
    return render_template('test.html', error=func1)

if __name__ == '__main__':
    app.run()

请求响应

'''
获取当前请求的内容
1 先要导入request
2 直接用request.方法,属性
返回的时候,如果需要设置额外的响应参数,比如cookie,heard
1 response=make_response(四剑客)
2 response.设置属性=“属性值”
3 return response
'''

from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response

app = Flask(__name__)

@app.route('/login.html', methods=['GET', "POST"])
def login():

    # 请求相关信息
    # request.method  提交的方法
    print("request.method",request.method)
    # request.args  get请求提及的数据
    print("request.args", request.args)
    # request.form   post请求提交的数据
    # request.values  post和get提交的数据总和
    # request.cookies  客户端所带的cookie
    # request.headers  请求头
    # request.path     不带域名,请求路径
    # request.full_path  不带域名,带参数的请求路径
    # request.script_root
    # request.url           带域名带参数的请求路径
    # request.base_url      带域名请求路径
    # request.url_root      域名
    # request.host_url      域名
    # request.host          127.0.0.1:500
    # request.files
    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(f.filename))

    # 响应相关信息
    # return "字符串"
    # return render_template('html模板路径',**{})
    # return redirect('/index.html')
    #return jsonify({'k1':'v1'})

    # response = make_response(render_template('index.html'))
    # response是flask.wrappers.Response类型
    # response.delete_cookie('key')
    # response.set_cookie('key', 'value')
    # response.headers['X-Something'] = 'A value'
    # return response
    response1=make_response(render_template('test.html'))
    #response1.set_cookie('key_sss', 'valuessbbsd')
    # response1.delete_cookie('key_sss')
    response1.headers['sb'] = 'asdas'
    return response1

if __name__ == '__main__':
    app.run()

session

# 设置:session['username'] = 'xxx'
# 在django中发什么三件事,1,生成一个随机的字符串 2 往数据库存 3 写入cookie返回浏览器
# 在flask中他没有数据库,但session是怎样实现的?
    # 生成一个密钥写入这个cookie,然后下次请求的时候,通过这个cookie解密,然后赋值给session
    #我们通过app.session_interface来查看

# 删除:session.pop('username', None)


# session源码的执行流程
"""
-save_seesion
    -响应的时候,把session中的值加密序列化放到了cookie中,返回到浏览器中
-open_session
    -请求来了,从cookie中取出值,反解,生成session对象,以后在视图函数中直接用sessoin就可以了。
"""

from flask import Flask,session

app = Flask(__name__)
app.debug=True
app.secret_key="ajsdklas" # 设置密钥
app.config['SESSION_COOKIE_NAME']="session_key"
# app.session_interface
@app.route("/")
def index():
    session['name']="sb"
    return "ok"

@app.route("/test")
def test():
    print(session['name'])
    return "ok1"

if __name__ == '__main__':
    app.run()

闪现flash

'''
1 设置flash
    1.1 flash("要传递的值",category="分类的名称"),如果不传默认是message
    本质:session['_flash']
2取flash设置的值我们用get_flashed_messages
 2.1 get_flashed_messages(with_categories=False, category_filter=()),
    2.1.1如果不传递 category_filter,取出上面存储的所有分类传递的值
    2.1.2如果不传with_categories就只取值,不取分类的名字,如果传值,就获取 分类名和分类值

3 这个flash只能一个视图函数中取,只要有一个视图函数取过了,那其他视图函数就不能获取
    本质:session.pop("_flash")
    3.1 但是在同一个视图函数里面可以无限的取值
'''

from flask import Flask,flash,get_flashed_messages,request,redirect

app = Flask(__name__)
app.debug=True
app.secret_key = 'asdfasdf'

@app.route('/index')
def index():
    # 从某个地方获取设置过的所有值,并清除。
    #flash('超时错误',category="x1")
    flash("它过来了,你要小心")
    flash("我是第二个",category="ss")
    return "ssdsdsdfsd"
    # return redirect('/error')


@app.route('/error')
def error():
    """
    展示错误信息
    :return:
    如果get_flashed_messages(with_category=True)
    """
    #data = get_flashed_messages(category_filter=['x1'])
    data=get_flashed_messages(with_categories=True,category_filter=['ss'])
    data1 = get_flashed_messages(with_categories=True, category_filter=['ss'])
    print(type(data))
    print(data1)
    return "错误信息:%s" %(data,)


if __name__ == '__main__':
    app.run()

请求扩展

"""
1 before_request 请求之前
    1.1可写多个befor_request函数
    1.2而且是从上往下执行的
    1.3 一旦有返回值,请求的视图函数不会执行,已经剩下的befor_request不会执行

2 after_request 请求之后
    2.1可以写多个after_request函数
    2.2 所有的after_request是从下往上执行,和befor_request相反
    2.3 无论 befor_request有没有返回值,我的after_request都会执行
    2.4 必须接收response,而且必须返回response

3 before_first_request 是我项目启动后,接受到的第一个请求,会执行该函数,后面就不会在执行

4 teardown_request(e)
    4.1 这是e 是接收我服务器抛出的异常
    4.2 无论我服务器有没有错误,都会执行该函数
    4.3 虽然能接收异常,但是没有办法处理异常

5 errorhandler(500)
    5.1 参数的中值为错误码
    5.2 当服务器抛出对应状态码的异常,就会执行该函数
    5.3 并且该函数可以处理异常,让用户无法感知,服务器错误
    5.4 每一个错误码,都需要一个对应的函数进行处理
"""

# 第一次请求时,跟浏览器无关
@app.before_first_request
def first():
    pass

# 基于它做用户登录认证
# 类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情
@app.before_request
def process_request(*args,**kwargs):
    if request.path == '/login':
        return None
    user = session.get('user_info')
    if user:
        return None
    return redirect('/login')

# 类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常
@app.after_request
def process_response1(response):
    print('process_response1 走了')
    return response

# 每一个请求之后绑定一个函数,即使遇到了异常
@app.teardown_request
def ter(e):
    pass

# 全局前端页面都可以获取数据
@app.template_global()
def sb(a1, a2):
    return a1 + a2
#{{sb(1,2)}}

# 过滤器
@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3
#{{ 1|db(2,3)}}

中间件

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World!'
# 模拟中间件
class Md(object):
    def __init__(self,old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app

    def __call__(self,  environ, start_response):
        print('开始之前')
        ret = self.old_wsgi_app(environ, start_response)
        print('结束之后')
        return ret

if __name__ == '__main__':
    #1我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法
    #2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
    #3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
    #4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
    #把原来的wsgi_app替换为自定义的,

    app.wsgi_app = Md(app.wsgi_app)
    app.run()
02-14 00:58