Bootstrap

Flask03_路由传参

# encoding=utf-8
"""
1、@app.route("/路由匹配/"):代表资源在服务器上的位置
(1)路由:Flask根据http请求的url在路由表中和定义好的进行匹配,找到对应的函数处理这个请求,此过程保存一个url到函数的映射关系称之为路由router
(2)Flask通过装饰器@app.route("路由后半部分")来定义,route内部代码会将其余前面的url拼接成一条完整的路由
(3)通过装饰器装饰在视图函数上,是指向视图函数的标志,用户可以通过url来访问,服务器通过url路由引导获取到:@app.route("/地址(一节)/")
(4)路由编写规则
    A、开头必须"/":强制规则,开头没有"/"是不合法的
    B、结尾添加"/":标准的url,类似文件夹,访问无"/"的url时,Flask会重定向,自动在结尾添加
    C、结尾没有"/":类似文件,访问添加了"/"的url时,会报404错误,可以保持url唯一,帮助搜索引擎避免重复索引同一页面
    D、路由是可以重复的
(5)根目录:网站服务启动的目录就是根目录
(6)对于视图函数,代表视图函数的路由;对于静态资源,代表放在服务器当前web服务的根目录的位置
2、视图函数
(1)视图是处理请求,返回响应的代码块,函数名字不能重名
(2)函数的名字与路由的名字可以不一致(一般为了简明,保持一致)
3、路由讲解
(1)route装饰器:装饰视图函数,更加方便、优雅地写应用的URL
    def route(rule, **options):
        def decorator(f):
            add_url_rule(rule, f.__name__, **options)
            view_functions[f.__name__] = f
            return f
        return decorator
    A、首先会调用add_url_rule 法,将装饰器中的URL规则添加进Map实例中,视图函数的名字会作为endpoint进行传递
    B、在应用的view_functions中增加endpoint和视图函数的对应关系,可以在请求成功时方便地调用对应的视图函数
(2)add_url_rule
    def add_url_rule(rule, endpoint, **options):
        options['endpoint'] = endpoint
        options.setdefault('methods', ('GET',))
        url_map.add(Rule(rule, **options))
    A、用来添加url与视图函数的映射,默认会使用view_func的名字作为endpoint,可以将URL和视图函数关联起来
    B、使用url_for时,要看映射时的endpoint参数,只要传递一条规则rule和一个endpoint即可
    C、可以传递一些关键字参数:路由rule、访问点endpoint、视图函数func
    D、调用方法后,会调用Map实例的add方法,会将URL规则添加进Map实例中
    >> app.add_url_rule(rule=路由,view_func=视图函数,endpoint=访问点)
(3)访问点endpoint:做反向解析
    A、视图函数中关于url_map视图的映射应该是:[url->methods->endpoint]
    B、methods=["POST","GET"]):methods用来限制请求方式
    C、利用url_map找到所请求URL对应的endpoint访问点(通过url地址映射到端点endpoint),利用view_functions表(默认空字典,存储endpoint:view_func键值对)查找到访问点对应的视图函数,最终匹配到函数,执行响应的功能函数
    D、一个实例对象app的本质过程是通过url先找到endpoint的值(url_map映射),然后endpoint在字典view_functions中找到视图函数view_func,同一实例对象app中试图函数名可以相同,但endpoint不能相同
    E、url_map:维护URL规则和endpoint的映射
    F、view_functions={键:值}:维护endpoint和视图函数的映射
    G、默认访问点:使用route装饰器注册路由时,默认使用被装饰函数的 函数名作为访问点
    H、自定义访问点:在使用route装饰器或调用add_url_rule()方法注册路由时,使用endpoint关键字参数可以改变默认行为
    I、app.add_url_rule("/index2/<int:yy>",view_func=index2):Flask中只有有名分组,yy用于接收参数
    app.add_url_rule("/", view_func=index,endpoint="index12333444",methods=["POST","GET"])
    def index1():
        print(url_for("index12333444"))
        return "123"
    app.add_url_rule("/index1",view_func=index1,strict_slashes=False,redirect_to="/index2")
    def index2(yy):
        print(yy)
        return "123445"
    #只有有名分组
    app.add_url_rule("/index2/<int:yy>",view_func=index2)
    if __name__ == '__main__':
        app.run()
(4)变量规则
    A、通过把url的一部分标记为<variable>就可以在url中添加变量,标记的部分会作为关键字参数传递给函数
    B、通过使用<converter:variable>,可以选择性的加上一个转换器,为变量指定规则
        from markupsafe import escape
        @app.route('/user/<user>')
        def show_user(user):
            return f'escape转变:{escape(user)}'
4、Restful URL
(1)Restful URL可以看做是对URL参数的替代,得到的变量默认为str对象
(2)内置转换机制可以在route中指定转换类型,传递的数据类型若与指定类型不同时,会得到404丢失页面响应
(3)内置转换机制支持int整数、float浮点数、path路径类型数据
(4)定义转换器
    A、自定义的转换器是一个继承werkzeug.routing的BaseConverter类
    B、to_python方法用于将url中的变量转换后供被@app.route包装的函数使用,返回值会传递到view函数中作为参数
    C、to_url方法用于flask.url_for中的参数转换,返回值会调用url_for函数的时候生成符合要求的url形式
    D、app.url_map属性:是一个定义在werkzeug.routing模块中的Map类,为了给应用增加一些URL规则,生成对应的正则表达式进行URL匹配
    E、app.url_map.converters['自定义规则名称'] = 自定义转换器类,将自定义的类映射到app.url_map.converters
(5)路由正则
    A、写类,继承BaseConverter
    B、注册:app.url_map.converters['regex'] = RegexConverter
    C、使用:@app.route('/index/<regex("\d+"):nid>'),正则表达式会当作第二个参数传递到类中
    from flask import Flask, views, url_for
    from werkzeug.routing import BaseConverter
    app = Flask(import_name=__name__)
    # 自定义URL匹配正则表达式
    class RegexConverter(BaseConverter):
        def __init__(self, map, regex):
            super(RegexConverter, self).__init__(map)
            self.regex = regex
        # 路由匹配时,匹配成功后传递给视图函数中参数的值
        def to_python(self, value):
            print("to_python",type(value),value)
            return int(value)
        # 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        def to_url(self, value):
            print("to_url", type(value), value)
            val = super(RegexConverter, self).to_url(value)
            return val+"123"
    # 添加到flask中
    app.url_map.converters['regex'] = RegexConverter
    @app.route('/index/<regex("\d+"):nid>')
    def index(nid):
        print("nid",type(nid),nid)
        print(url_for('index', nid='888'))
        return 'Index'
    if __name__ == '__main__':
        app.run()
5、url_for(视图函数名,传递参数值)反转视图函数
(1)用于构建指定函数的url
    A、把函数名称作为第一个参数
    B、可以接受任意个关键字参数,每个关键字参数对应url中的变量
    C、未知变量将添加到url中作为查询参数
    D、url反转:根据视图函数名称得到当前所指向的url
(2)为什么不写死,而是反转

(1)构建url原理
    A、使用endpoint通过反向机制构建URL路径,可以以软编码的形式生成url,提供开发效率
    B、最简单的用法是以视图函数名作为参数,返回对应的url
    C、若想要完整的URL,可以设置_external为Ture
        url_for('static',_external=True)
(2)加载访问静态文件:指定目录下static文件,使用/static访问
    文件存储在static/style.css
    url_for('static', filename='style.css')
(3)指定函数构造URL
    A、接受函数名作为第一个参数
    B、接受URL规则中对应的变量作为参数
    C、未知变量部分会添加到URL末尾?后作为查询参数
(4)构建URL而不是拼URL的原因
    A、反向构建通常比硬编码的描述性更好:允许一次性修改URL
    B、URL构建会转义特殊字符和Unicode数据
    C、若应用不位于URL根路径,url_for()会进行妥善处理(不是/,而是/myapp)
(5)总结简述
    A、视图函数:参数是endpoint,默认函数名view_func和端点endpoint相同(要反转的url就是视图函数所在路由)
    B、传递参数:传入在路由中已经定义的参数,路由直接拼接;传入在路由中没有定义的参数,会以查询字符串('?参数名=参数值')的形式反转出来
    C、如果修改url,并不修改url对应的函数名,就不用到处去替换url;url_for会自动处理特殊字符,不需要手动处理
    D、示例:url_for('static',_external=True,filename='imgs/test.png')
        返回的url是 http://localhost/static/imgs/test.png
(6)附带参数讲解
    A、endpoint:URL的端点(默认函数名view_func)
    B、values:URL的变量参数
    C、_external:设置为True则生成一个绝对路径URL
    D、_scheme:一个字符串指定所需的URL方案(_external必须为True,否则抛出ValueError)
    E、_anchor:给URL添加一个mao
    F、_method:显示地调用HTTP方法
(9)url_for和redirect区别
    A、url_for用来拼接url:可以使用程序url映射中保存的信息生成url
    B、url_for()函数最简单的用法是以视图函数名作为参数,返回对应的url
        调用url_for('index')得到的结果是:index视图的路由"/"
    C、redirect是重定向函数,输入一个url后,自动跳转到另一个url所在的地址
(10)test_request_context()告诉Flask正在处理一个请求,并没有真正的请求
    with app.test_request_context():
        print(url_for('index'))
        print(url_for('login'))
        print(url_for('login', next='/'))
        print(url_for('profile', username='John Doe'))
6、动态路由介绍
(1)Flask根据HTTP请求的URL在路由表中匹配定义好的路由规则,找到对应的函数处理请求,查询路由表的这个过程需要一个URL到函数的映射关系,这个映射关系就称之为路由
(2)路由和函数需要的名称可以不对应,对应是为了提高可读性
(3)路由不可以合并,每个路由都是一个装饰器,被装饰的函数,为视图函数,名称不可以重复
(4)由app.route方法安装装饰器语法定义,flask的路由必须有/,否则会报ValueError的错误
(5)网站开发时,访问内容变化,路由随之变化,网站的资源也会随之变化
(6)可以通过路由修改查询的内容,本身可以把接收数据中的一部分传递给视图函数
(7)前端部分可以通过页面的a标签的href属性指向目的路由去跳转页面
(8)在路由上,变量数据是由<>包围的部分,匹配到的内容会作为参数传递给视图函数(名称一致)
(9)Flask路由需要使用装饰器的形式定义,路由定义必须以’/’ 开头
7、路由传参(动态路由)
(1)将路由参数中的部分数据使用<>包含,可以传递参数
(2)/<string:data>/字符串(默认):数字、字符串-->字符串类型
(3)/<int:data>/整数:整数-->整数类型
(4)/<float:data>/浮点数:浮点数-->浮点数类型
(5)/<path:data>/路径:路径(多/分割)-->字符串类型
(6)/<uuid:data>/uuid:唯一标识符-->uuid字符串
"""
# 导入模块
from flask import Flask

# 创建web服务器(http)实例:内置方法__name__是预定义变量,被设置为使用本模块,html存放的路径,静态文件的路径
app = Flask(__name__)

# route装饰器装饰视图函数
@app.route("/default")
# 视图(编写功能)
def default():
    # 访问页面的时候,这一部分会作为参数传入视图函数,默认数据类型是字符串
    return '默认不传数据'


# route装饰器装饰视图函数
@app.route("/point", endpoint='自定义访问点')
# 视图(编写功能)
def point():
    # 访问页面的时候,这一部分会作为参数传入视图函数,默认数据类型是字符串
    return '设定访问点'


# 整数类型参数限制,浏览器地址输入整数时传递
@app.route("/index/<int:age>/")
def int_demo(age):
    # 访问页面的时候,数据类型会自动将参数转换成整数类型
    return f'查询年龄:我{age}岁了'


# 字符串类型参数限制,浏览器地址输入整数时传递(默认传递类型)
@app.route("/index/<string:name>/")
def string_demo(name):
    # 访问页面的时候,数据类型会自动将参数转换成字符串
    return f'查询姓名:我叫{name}'


# 浮点数类型参数限制,浏览器地址输入浮点数时传递
@app.route("/index/<float:weight>/")
def float_demo(weight):
    # 访问页面的时候,数据类型会自动将参数转换成浮点数
    return f'查询体重:我{weight}千克'


# 路径类型参数限制(可以有多个"/"),浏览器地址输入整数时传递
@app.route("/index/<path:location>/")
def path_demo(location):
    # 访问页面的时候,数据类型会自动将参数转换成路径
    return f'查询地址:我来自{location}'


# uuid是一种号称在世界范围内唯一的编码
@app.route("/index/<uuid:id>/")
def uuid_demo(id):
    # 访问页面的时候,数据类型会自动将参数转换成uuid
    return f'查询唯一标识:我的唯一标识是{id}'

@app.route("/test/enumerate")
def enumerate():
    print("直接返回循环数据")
    for i in "abc":
        print(i)

    print("返回循环的数据和索引")
    for i in enumerate("abc"):
        print(i)

    print("去掉双引号数据和索引")
    for i, j in enumerate("abc"):
        print(i, j)

    print("索引值设定(从1开始)")
    for i, j in enumerate("abc", 1):
        print(i, j)
    return "enumerate返回值检测完毕~"

@app.route("/test/locals")
def hi():
    a = 1
    b = 2
    hi = 3
    print("hi--",locals())
    # 参数组解包,将当前函数所有的局部变量传入
    hello(**locals())

@app.route("/test/kwargs")
def hello(**kwargs):
    print("hello 函数")
    print("hello--",kwargs)

# 启动项目服务器--可以通过参数更改,通常网站的页面需要放到网站服务器上,用户无法双击打开
if __name__ == '__main__':
    app.run(
        # host:主机地址
        host="localhost",
        # port:访问端口
        port=80,
        # debug:调试模式,测试环境True,生产环境Fasle
        debug=True,
        # use_reloader:自动重启
        use_reloader=True
    )

;