• Flask 路由、视图、模版、闪现详解


    一、注册路由

    1、定义

    路由:指根据url定位到具体的类或者函数的程序,本质就是建立url跟程序之间的映射。flask中使用的路由被称之为注册路由

    2、路由传参

    2.1 动态传参

    # 动态传参语法
    @app.route(路径+/<参数名>/')
    #例子
    @app.route('/index/<id>/')
    def index(id)
        print(id)
        return id

    使用转换器进行对传参的类型进行限定

    string 默认的数据类型,接收没有任何斜杆 /的字符串
    int 整型
    float 浮点型
    path 跟string类型类似,它可以接受斜杆/
    uuid uuid格式的字符串
    any 可以指定多种路径
    #使用方法
    @app.route('/index/<int:id>/')
    def index(id):
        return id
    
    # any类型的用法、它可以指定多种路径
    @app.route('/<any(user,admin):who>/<id>/')
    def home(who,id):
        if who== 'user':
            return '这里是普通用户{}的主页'.format(id)
        else:
            return '这里是管理员{}的主页'.format(id)    

    动态路由一般可以用来提高网站的曝光率

    2.2 查询字符串传参(也就是?传参)

    注意:request.args获取的是解析后的字典类型,request.query_string获取的是问号后的原生字符串。

    http://127.0.0.1:5000/?name='hello'&age=18
    @app.route('/')
    def home():
        print(request.args)
        #>: ImmutableMultiDict([('name', "'hello'"), ('age', '18')])
        print(request.query_string)
        #>: b'name=%27hello%27&age=18'
        return '这是跟路径'

    3、自定义动态路由过滤(转换器)

    3.1 正则匹配

    from flask import Flask, views, url_for
    from werkzeug.routing import BaseConverter
    
    app = Flask(__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()

    注意:必须继承werkzeug.routing 的BaseConverter类,regex属性指定路由过滤规则,app.url_map.converters本质就是一个字典

    3.2 自定义动态路由过滤器处理动态路由

    # -*-coding:utf-8 -*-
    from flask import Flask,url_for
    from werkzeug.routing import BaseConverter
    
    app = Flask(__name__)
    
    class ListConverter(BaseConverter):
        regex = '.*'
        def to_python(self, value):
            '''
            对动态参数进行处理
            :param value: 路由里的动态参数
            :return: 处理好的动态参数结果
            '''
            print(value) # a+b+c
            return value.split('+')
        def to_url(self, value):
            '''
            搭配url_for使用,对value进行处理
            :param value: url_for指定的动态参数
            :return:
            '''
            print('to_url:',value) #结果:to_url: ['a', 'b']
            return '+'.join(value)
    
    app.url_map.converters['list']=ListConverter
    
    @app.route('/test/<list:ids>/') #注意这里没有设置endpoint,所以默认是home
    def home(ids):
        # 对http://127.0.0.1:5000/test/a+b+c/发起请求
        print('home:',ids) # 结果 ['a', 'b', 'c']
        print(url_for('home',ids=['a','b'])) #结果 /test/a+b/
        return 'home'
    
    if __name__ == "__main__":
        app.run(debug=True)

    总结:to_python()方法是对动态路由的参数进行处理,to_url是对url_for()函数传入的动态参数进行处理

    4、endpoint参数

    4.1 endpoint 简介

    endpoint是注册路由中的一个参数,也叫端点(类似函数的别名)通过url_for函数+endpoint参数值,可以反解出url

    @app.route('/index11',endpoint='i')
    def index():
        print(url_for('i')) #打印结果:/index11

    4.2、对endpoint参数有关源码分析

    def route(self, rule, **options):
        def decorator(f):
            # 1、先从options中获取endpoint值,如果没有,则赋值None给endpoint
            endpoint = options.pop("endpoint", None)
            # 2、将endpoint传到add_url_rule函数(也是注册路由的关键函数)中处理
            self.add_url_rule(rule, endpoint, f, **options)
            return f
    
        return decorator
    def add_url_rule(self,rule,endpoint=None,view_func=None,
        provide_automatic_options=None,
        **options
        ):
        # 3、先判断endpoint是否为None  
        if endpoint is None:
            # 4、endpoint值为None的时候,调用_endpoint_from_view_func   
            endpoint = _endpoint_from_view_func(view_func)
        #4/7、 endpoint有值的时候,把它传给options    
        options["endpoint"] = endpoint
    def _endpoint_from_view_func(view_func):
        # 5、用断言来判断函数是否为None,是则报错
        assert view_func is not None, "expected view func if endpoint is not provided."
        # 6、返回一个函数的的函数名
        return view_func.__name__

     5、add_url_rule(): 注册路由的第二种方式

    def index():
        return '注册路由的另一种方式'
    
    app.add_url_rule('/index/',endpoint('自定义名字'),view_func=index(函数地址)

    6、注册路由中用到的参数

    # ----------常用参数--------------
    # @app.route()和app.add_url_rule参数
    rule      #路由路径
    view_func # 视图函数名称
    endpoint  # 端点名字,用于url_for反向解析url
    methods   # 允许请求的方式
    
    # -----------其他参数---------------
    # 1、对url是否加/是否有严格要求 
    strict_slashes=Flase  #访问http://127.0.0.1/index和http://127.0.0.1/index/都可以
    @app.route('/index', strict_slashes=True)  #仅可以访问http://www.xx.com/index
    
    # 2、重定向 redirect_to
    @app.route("/index",redirect_to='/home/') #当你访问index页面的时候,会跳到home页面去
    
    # 3、为函数提供默认参数值
    defaults = None #默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
    @app.route('/home',defaults={'k':'v'})
    def home(k):
        print(k) # v
    # 4、设置子域名 subdomain
    from flask import Flask,url_for
    
    app = Flask(__name__)
    app.debug = True
    '''
    先在hosts设置域名解析(就是在本机的hosts文件上编辑上域名对应ip的关系) 
    域名解析会先解析本地如果没有再解析dns服务器
    C:WindowsSystem32driversetchosts
    
    127.0.0.1 mark.com
    127.0.0.1 admin.mark.com
    
    '''
    app.config['SERVER_NAME'] = 'mark.com:5000' # 这个代表访问这个域名的时候要访问5000端口
    
    @app.route("/")
    def index():
        return '设置域名成功'
    
    @app.route("/admin_demo/",subdomain='admin')
    def admin_demo():
    
        return '设置子域名成功'
    
    '''
    在浏览器中访问主域名
    mark.com:5000/
    在浏览器中访问子域名
    admin.mark.com:5000/admin_demo/
    
    注意:后面跟的path路径部分正常写
    '''
    if __name__ == '__main__':
        app.run(host='127.0.0.1',port=5000) # 测试服务器不稳定,尽量手动制定ip和端口

    二、视图

    1、视图函数

    视图函数跟django的视图函数类似,只不过在视图函数中加装饰器有点不一样,flask中需要将装饰器卸载注册路由下面,视图函数上面,同时,装饰器内部要使用@wraps(func)方法,用于保护被装饰函数的属性

    from flask import Flask, request
    from functools import  wraps
    
    app = Flask(__name__)
    
    def login_verify(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            user_name = request.args.get('user')
            password = request.args.get('password')
            if user_name == 'mark' and password == '123':
                return func(*args,**kwargs)
            else:
                return '请登录'
        return wrapper
    
    @app.route('/my_info/')
    @login_verify
    def my_info():
        return '个人信息页面'

    2、视图类

    2.1 标准类视图类

    '''
    1、继承flask.views.View
    2、注册路由:app.add_url_rule(rule,endpoint,view_func)
    --rule:路由地址
    --endpoint: 端点
    --view_func: 函数名称(不用加括号)
    3、重写dispatch_request方法
    '''
    # -*-coding:utf-8 -*-
    from flask import Flask,views,url_for
    
    app=Flask(__name__)
    
    class S_Test(views.View):
        def dispatch_request(self):
            print(url_for('List')) #/stest
            return '这是标准视图类'
    '''
    注意:如果设置了endpoint,那么使用url_for反转的时候,就要用endpoint的值
         如果没有,则可以直接用as_view中的指定的视图名字来作为反转
         as_view('视图名字')
    '''
    app.add_url_rule('/stest',view_func=S_Test.as_view('List'))
    if __name__=='__main__':
        app.run(debug=True)

    2.2 基于调度方法的视图类

    '''
    1、继承flask.views.MethodView
    2、指定支持请求类型 methods=[]
    3、指定使用哪些装饰器 decorators = []
    4、写相应的请求函数
    5、注册路由
    '''
    from flask import Flask,views,url_for
    from functools import wraps
    
    app=Flask(__name__)
    
    class Test(views.MethodView):
        methods = ['GET',"POST"]  #设置可以接收的请求方法
        decorators = [auth]  # 指定装饰器,注意不能添加单引号或者双引号
        # get请求方法
        def get(self):
            return '这是get请求方法'
        # post请求方法
        def post(self):
            return '这是post请求方法'
    # 同样,如果没有指定endpoint,url_for反转的时候,同样是使用as_view中的name值
    app.add_url_rule('/test',view_func=Test.as_view(name='test1'))
    if __name__=='__main__':
        app.run(debug=True)

    三、模板引擎

    1、概述

    模版引擎:指实现视图的业务逻辑和返回给前端的页面逻辑分离的工具。

    作用:实现业务逻辑和页面逻辑的分离,实现动态的去渲染页面

    模版路径配置,可以在Flask类的template_folder参数设置

    app = Flask(__name__,template_folder='模板位置')
    
    app =Flask(__name__)
    app.template_folder='模版位置'

    2、模版传参

    # 第一种,在render_template中把参数传过去
    @app.route('/')
    def index():
        return render_template('index.html',name='hello',age=18)
    
    # 第二种,把参数放在字典中,将字典传递过去
    @app.route('/')
    def index():
        context_dict={
            'name':'hello',
            'age':18
        }
        return render_template('index.html',context=context_dict)
    # 第三种,将字典打散传递过去
    return render_template('index.html',**context_dict)
    
    # ------------前端对接收到参数的处理--------------------
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        # 参数关键词
        {{ name }}
        # 字典参数
        {{ context.name }}
        {{ context.get('age') }}
        {{context['name']}}
    </body>
    </html>

    3、模板引擎使用url_for

    注意:url_for在模板中用法跟在视图函数的用法一样,没有指定endpoint,就使用函数名,指定了,就使用endpoint的值进行反转

    # 例子
    @app.route('/index')
    def index():
        return render_template('index.html')
    @app.route('/home',endpoint='h')
    def home():
        return render_template('index.html')
    
    # html文件
    <a href="{{ url_for('h') }}">home</a>
    <a href="{{ url_for('index') }}">index</a>
    #这句会报错,因为home函数的路由已经设置了endpoint
    <a href="{{ url_for('home') }}">home1</a> 

    4、jinja2控制语句使用

    # 控制语句都是以{% ... %} 开始 ,以{ %end...% }结束

    4.1 逻辑语句和if 语句

    '''
    判断: >、<、<=、==、!=
    逻辑:and、or、not、()
    '''
    { % if age>18 %}
        ...
    {% elif age ==9 %}
        ...
    {% else %}
        ...
    {%endif %} #表示结束判读

    4.2 循环语句和for循环

    # 遍历列表,可迭代对象,字典等
    {% for dict in d %}
         ...
    {% else %}
         ... # 遍历没有内容,才会执行else,for else逻辑在python是没有的
    {% endfor %}
    # 反转遍历
    {% for dict in d | reverse %}
    #------------ for 常用循环变量--------------
    loop.index     #当前循环的索引(从1开始)
    loop.index()   #当前循环的索引(从0开始)
    loop.first       #是否是第一次循环,是返回True,否则返回Flase
    loop.last       #是否是最后一次循环,是返回True,否则返回Flase
    loop.length    #总共可以循环的次数 / 迭代器的长度
    
    # 例子
     {% for college in colleges %}
          {% if loop.first %}
    <tr style="background: blue">
    {% elif loop.last %} <tr style="background: yellow "> {% else %} <tr> {% endif %} <td>{{ loop.index }}</td> <td>{{ loop.index0 }}</td> <td>{{ college.name }}</td> <td>{{ loop.length }}</td> </tr> {% endfor %}

    5、静态文件在模板中的使用

    {{ url_for('static',filename='相对于static文件夹的路径') }}
    <!DOCTYPE html>
    <html lang="en">
    <head>
     ...
        <script src="{{ url_for('static',filename='js/demo.js') }}"></script>    
    </head>
    ....

    6、模板继承

    定义一个基模版,在基模版中定义一些block块,以便给子模版实现自己的功能

    # 1、基模版parent.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    # top是自己定义的变量名
    {% block top %}
       <p>我是父模版</p>
    {% endblock %}
    </body>
    </html>
    # 2、子模板son.html继承parent.html
    {% extends 'parent.html' %}
    {% block top %}
        {{ super() }}  #表示继承父模板中的本块的代码
    <p>我继承了parent模版</p>
    {% endblock %}

    四、闪现

    1 定义

    闪现:flask提供的一个简单的方法,用来向用户反馈信息,本质是将信息放在session中,必须设置secret_key,下次请求的时候,再从session中获取。

    注意:闪现有效期只有一次,当下一次请求获取闪现的信息后,它就失效了

    2 用法

    from flask import Flask,flash,make_response,get_flashed_messages
    # 需要导入flash、get_flashed_messages 用来设置和获取闪现值
    app=Flask(__name__)
    app.secret_key='shanxian'
    
    @app.route('/')
    def home():
        flash('欢迎来到首页')  #设置闪现值
        return 'index'
    
    @app.route('/index')
    def index():
        a=get_flashed_messages() #获取闪现值
        return 'index11'

    前端获取闪现信息

    {% with messages= get_flashed_messages() %} # 获取所有闪现信息,返回的是列表
        {% for m in messages %}
        <li>{{ m }}</li>
        {% endfor %}
    {% endwith %}

    3 分类闪现

    默认分类是:message

    #1、设置:
    flash('hello',category='test') 
    #
    flash('hello','test')
    # 2、取值,获取所有闪现信息的类别和内容
    res=get_flashed_messages(with_categories=True)
    
    # ------------前端获取(注意with_categories=true别忘记设置)---------------
    {% with messages= get_flashed_messages(with_categories=true) %} # 获取所有闪现信息,返回的是列表
        {% for c,m in messages %}
        <li>{{ m }},{{ c }}</li>
        {% endfor %}
        {{ messages }}
        {% endwith %}
    ''' 结果如下:c是分类,m是闪现信息
    test111,error
    test222,tes
    test333,test3
    [('message', '欢迎来到首页'), ('error', 'test111'), ('tes', 'test222'), ('test3', 'test333')]
    '''

    4 过滤闪现信息( category_filter参数)

    #-----------后端视图函数过滤-----------------
    #默认category_filter =message
    get_flashed_messages(category_filter=['类名'])
    
    # -----------前端过滤闪现信息--------------
    {% with messages= get_flashed_messages(category_filter=['test']) %} # 获取test类的闪现信息,返回的是列表
        {% for m in messages %}
        <li>{{ m }}</li>
        {% endfor %}
    
    {% endwith %}
  • 相关阅读:
    ActiveX Demo
    VC6 DLL exports
    进程间通信:剪切板
    Hook编程2:全局钩子
    Cookieless Session In WebService
    Report predicts possible PS3 launch delay
    原来是PS过的
    Xbox360日本卖不动.历代主机首周销量对比
    DirectX SDK (February 2006)
    vbo的速度问题,没有想象中快
  • 原文地址:https://www.cnblogs.com/nq31/p/14312252.html
Copyright © 2020-2023  润新知