Flask框架之路由

13 篇文章 0 订阅

1. 添加路由

1.1 添加路由源码分析

添加路由方式如下:

@app.route('/index',methods=['GET','POST'])
def index():
    return 'index页面'

我们深入看route方法源码如下:

class Flask(_PackageBoundObject):
  	...
  	def route(self, rule, **options):
        """A decorator that is used to register a view function for a
        given URL rule.  This does the same thing as :meth:`add_url_rule`
        but is intended for decorator usage::

            @app.route('/')
            def index():
                return 'Hello World'

        For more information refer to :ref:`url-route-registrations`.

        :param rule: the URL rule as string
        :param endpoint: the endpoint for the registered URL rule.  Flask
                         itself assumes the name of the view function as
                         endpoint
        :param options: the options to be forwarded to the underlying
                        :class:`~werkzeug.routing.Rule` object.  A change
                        to Werkzeug is handling of method options.  methods
                        is a list of methods this rule should be limited
                        to (``GET``, ``POST`` etc.).  By default a rule
                        just listens for ``GET`` (and implicitly ``HEAD``).
                        Starting with Flask 0.6, ``OPTIONS`` is implicitly
                        added and handled by the standard request handling.
        """

        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator

route函数即一个闭包函数,最终返回decorator函数

add_url_rule方法解析

    @setupmethod
    def add_url_rule(
        self,
        rule,
        endpoint=None,
        view_func=None,
        provide_automatic_options=None,
        **options
    ):
        """Connects a URL rule.  Works exactly like the :meth:`route`
        decorator.  If a view_func is provided it will be registered with the
        endpoint.

        Basically this example::

            @app.route('/')
            def index():
                pass

        Is equivalent to the following::

            def index():
                pass
            app.add_url_rule('/', 'index', index)

        If the view_func is not provided you will need to connect the endpoint
        to a view function like so::

            app.view_functions['index'] = index

        Internally :meth:`route` invokes :meth:`add_url_rule` so if you want
        to customize the behavior via subclassing you only need to change
        this method.

        For more information refer to :ref:`url-route-registrations`.

        .. versionchanged:: 0.2
           `view_func` parameter added.

        .. versionchanged:: 0.6
           ``OPTIONS`` is added automatically as method.

        :param rule: the URL rule as string
        :param endpoint: the endpoint for the registered URL rule.  Flask
                         itself assumes the name of the view function as
                         endpoint
        :param view_func: the function to call when serving a request to the
                          provided endpoint
        :param provide_automatic_options: controls whether the ``OPTIONS``
            method should be added automatically. This can also be controlled
            by setting the ``view_func.provide_automatic_options = False``
            before adding the rule.
        :param options: the options to be forwarded to the underlying
                        :class:`~werkzeug.routing.Rule` object.  A change
                        to Werkzeug is handling of method options.  methods
                        is a list of methods this rule should be limited
                        to (``GET``, ``POST`` etc.).  By default a rule
                        just listens for ``GET`` (and implicitly ``HEAD``).
                        Starting with Flask 0.6, ``OPTIONS`` is implicitly
                        added and handled by the standard request handling.
        """
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options["endpoint"] = endpoint
        methods = options.pop("methods", None)

        # if the methods are not given and the view_func object knows its
        # methods we can use that instead.  If neither exists, we go with
        # a tuple of only ``GET`` as default.
        if methods is None:
            methods = getattr(view_func, "methods", None) or ("GET",)
        if isinstance(methods, string_types):
            raise TypeError(
                "Allowed methods have to be iterables of strings, "
                'for example: @app.route(..., methods=["POST"])'
            )
        methods = set(item.upper() for item in methods)

        # Methods that should always be added
        required_methods = set(getattr(view_func, "required_methods", ()))

        # starting with Flask 0.8 the view_func object can disable and
        # force-enable the automatic options handling.
        if provide_automatic_options is None:
            provide_automatic_options = getattr(
                view_func, "provide_automatic_options", None
            )

        if provide_automatic_options is None:
            if "OPTIONS" not in methods:
                provide_automatic_options = True
                required_methods.add("OPTIONS")
            else:
                provide_automatic_options = False

        # Add the required methods now.
        methods |= required_methods

        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError(
                    "View function mapping is overwriting an "
                    "existing endpoint function: %s" % endpoint
                )
            self.view_functions[endpoint] = view_func

route和app_url_rule方法参数介绍

rule,											即URL规则,如:'/index'
view_func,								视图函数名称
methods=None,							即该URL支持的请求方式,如:methods=['GET','POST'];
endpoint=None,						即指定该URL的别名,如:endpoint='n1',用于反向生成URL
defaults=None,						默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
strict_slashes=None,			对URL最后的 / 符号是否严格要求
redirect_to=None,					重定向到指定地址
subdomain=None,						子域名访问

分析decorator函数

		将视图函数(如index函数),作为参数传入decorator函数,然后执行add_url_rule方法,将rule/路径信息、f/视图函数、**optins/访问方法 加入到路由的规则当中

也就是说,本质上是通过add_url_rule方法将url路径信息和视图函数添加到了路由信息表中的

那么我们从上可知,可以直接通过add_url_rule方法实现路由映射,如下:

def login():
    return 'login页面'
# 路由添加方式二:
app.add_url_rule('/login',view_func=login)

1.2 添加路由的两种方式

如下

from flask import Flask,render_template,redirect

app = Flask(__name__)

'''
1. 执行decorator = app.route('/index',methords=['GET','POST'])
2. @decorator
    - 执行decorator(index)
'''

# 路由添加方式一:
@app.route('/index',methods=['GET','POST'])
def index():
    return 'index页面'

def login():
    return 'login页面'
  
# 路由添加方式二:
app.add_url_rule('/login',view_func=login)

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

注意:

​ 通常在Flask中我们只用第一种方式(也就是装饰器的方法)来添加路由,第二种只是用来方便理解路由添加原理的方式,实战中并不会用到

2. 反向生成URL

通过url_for方法反向生成URL

2.1 导入url_for方法

from flask import Flask,url_for

2.2 定义别名

通过route方法中的endpoint参数给url定义别名,避免url过长书写不便

@app.route('/index',methods=['GET','POST'],endpoint='dex')
def index():
    return 'index页面'

2.3 反向生成url(通过别名)

通过url_for方法反向生成url

url_for('dex')	# dex为定义的别名
print(url_for('dex'))	# 打印结果:/index

2.4 反向生成url(没有别名的情况下)

如果没有给url定义别名,那么可以直接通过视图函数名来反向生成URL

@app.route('/showalias')
def showaliasabc():
    print(url_for('showaliasabc'))  # 如果不起别名,默认可以通过函数名反向生成URL
    return '别名展示页面'
  
# 打印结果:/showalias

2.5 示例

代码示例

from flask import Flask,render_template,redirect,url_for

app = Flask(__name__)

@app.route('/index',methods=['GET','POST'],endpoint='dex')
def index():
    return 'index页面'

@app.route('/login',methods=['GET','POST'],endpoint='in')
def login():
    return 'login页面'

@app.route('/logout',methods=['GET','POST'])
def logout():
    return 'logout页面'

@app.route('/showalias')
def showaliasabc():
    print(url_for('dex'))
    print(url_for('in'))
    print(url_for('logout'))
    print(url_for('showaliasabc'))  # 如果不起别名,默认就是函数名
    return '别名展示页面'

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

打印结果

127.0.0.1 - - [29/Mar/2020 17:25:59] 
"/index
/login
/logout
/showalias
GET /showalias HTTP/1.1" 200 -

3. 自定义路由转换器

3.1 路由转换初识

见如下代码:

from flask import Flask,render_template,redirect,url_for

app = Flask(__name__)

@app.route('/index/<int:nid>',methods=['GET','POST'])
def index(nid):
    print(nid,type(nid))
    return "index页面"

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

通过http://127.0.0.1:5000/index/12访问web,查看后台打印内容:

12 <class 'int'>
127.0.0.1 - - [29/Mar/2020 18:37:33] "GET /index/12 HTTP/1.1" 200 -

注:

<int:nid>决定了url带参必须是int类型的,否则会报错

3.2 常用的路由格式

如下,是常用的路由格式

@app.route('/user/<username>')      # 字符串
@app.route('/post/<int:post_id>')   # int类型
@app.route('/post/<float:post_id>') # float浮点型
@app.route('/post/<path:path>')     # 路径
@app.route('/login',methods=['GET','POST']) # 默认不传

常用路由系统有以上五种,所有的路由系统都是基于以下对应关系(也就是路由转换器)来处理的:

DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}

​ 比如说上例中中的<int:nid>,url本身是字符串格式,传参也是字符串,但是传递给视图函数的参数的数据类型却是int类型,这就是通过路由转换器IntegerConverter来实现的

​ 默认情况下,Flask的路由系统也就以上几种路由转换器

补充:UUID

# UUID
		- UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写
		- 简单说就是通过一系列算法,得到一个唯一值,在想要通过唯一值标记的情况下可以考虑用UUID
		- python可以通过导入uuid模块,然后通过uuid.uuid4()方法得到uuid值

3.3 自定义正则路由匹配

​ 由于Flask默认仅支持以上几种URL的书写方式,但是实际情况中我们可能对URL有更复杂的要求;Flask是支持自定义正则的方式来实现路由匹配的

from flask import Flask,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):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        :param value:
        :return:
        """
        return int(value)   # 此处将参数强转为int类型传递给视图函数,如果想要传递原生参数,可以不进行转换

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        :param value:
        :return:
        """
        val = super(RegexConverter, self).to_url(value)
        return val	# 在反解时,也可以return固定的值,当然基本不会这样做

# 添加到flask中;并命名该转换器名称为regex
app.url_map.converters['regex'] = RegexConverter


@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(nid,type(nid))
    print('999:',url_for('index',nid=999))
    print('nid:',url_for('index',nid=nid))
    return "index页面"


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

访问http://127.0.0.1:5000/index/18,后台打印结果如下:

18 <class 'int'>
127.0.0.1 - - [29/Mar/2020 19:22:45] "999: /index/999
nid: /index/18
GET /index/18 HTTP/1.1" 200 -

通过以上办法,Flask的路由系统中即可支持正则表达式了

4. app.route参数详解

常用参数

rule,											即URL规则,如:'/index'
view_func,								视图函数名称
methods=None,							即该URL支持的请求方式,如:methods=['GET','POST'];
endpoint=None,						即指定该URL的别名,如:endpoint='n1',用于反向生成URL
defaults=None,						默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
strict_slashes=None,			对URL最后的 / 符号是否严格要求
redirect_to=None,					重定向到指定地址
subdomain=None,						子域名访问

default

比如,当URL中没传参数,但是可以直接定义默认参数(如db=mysql)传递给视图函数

from flask import Flask

app = Flask(__name__)

@app.route('/index',methods=['GET','POST'],endpoint='idx',defaults={'db':'mysql'})
def index(db):
    print(db)
    return "index页面"

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

strict_slashes=None

对URL最后的"/"符号是否严格要求

@app.route('/index',strict_slashes=True)
	# 当该参数为True时,仅能访问 http://127.0.0.1:5000/index ;
@app.route('/index',strict_slashes=False)
	# 当该参数为False时,可访问 http://127.0.0.1:5000/index 或 http://127.0.0.1:5000/index/

redirect_to=None

重定向到指定的URL地址

from flask import Flask

app = Flask(__name__)

@app.route('/oldfunc/<int:nid>',redirect_to='/newfunc/<nid>')
def oldfunc(nid):
    print(nid)
    return '老页面'

@app.route('/newfunc/<int:nid>')
def newfunc(nid):
    print(nid)
    return '新页面'

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

如上,访问http://127.0.0.1:5000/oldfunc/2时,会自定跳转到http://127.0.0.1:5000/newfunc/2

subdomain=None

子域名访问

from flask import Flask

app = Flask(__name__)
app.config['SERVER_NAME'] = 'mlg.com:5000'

@app.route('/index',subdomain="<username>")
def index(username):
    print(username)
    return '获取子域名'

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

如上,可以获取到mlg这个子域名

5. 总结

@app.route('/index') --> 
route函数->decorator->add_url_rule --> 
add_url_rule函数-> rule = self.url_rule_class()->self.url_map.add(rule) -->
url_map->self.url_map = self.url_map_class() -->
url_map_class()->url_map_class = Map-->
class Map:->self._rules = []

也就是说:实例化后的Map,就相当于一个列表
map = [
    rule('/url01',函数1),
    rule('/url02',函数2),
    rule('/url03',函数3),
]
路由信息,会被添加到上述的列表中,用于url与视图函数的映射

注:无论是Django还是Flask,均是以路由关系创建为开始

-----
重点:
    - url
    - methods 允许的请求方法
    - endpoint url别名(默认是函数名)
    - @app.route('/index/<int:nid>/<int:nid2>')
    - url_for
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值