flask_之URL

URL篇

在分析路由匹配过程以前,咱们先来看看 flask 中,构建这个路由规则的两种方法:html

  1. 经过 @app.route() decorator前端

  2. 经过 app.add_url_rule,这个方法的签名为 add_url_rule(self, rule, endpoint=None, view_func=None, **options),参数的含义以下:python

    • rule: url 规则字符串,能够是静态的 /path,也能够包含 /flask

    • endpoint:要注册规则的 endpoint,默认是 view_func 的名字api

    • view_func:对应 url 的处理函数,也被称为视图函数数据结构

这两种方法是等价的,也就是说:app

@app.route('/')
def hello():
    return "hello, world!"

 也能够写成ide

def hello():
    return "hello, world!"

app.add_url_rule('/', 'hello', hello)

 其实,还有一种方法来构建路由规则——直接操做 app.url_map 这个数据结构。不过这种方法并非很经常使用,所以就不展开了函数

静态路由

@app.route('/')
def hello_world():
    # 变量能够经过赋值传到前端,前端能够经过Jinja语法{{}}渲染
    return render_template('t1.html', name='t1', age=16)

@app.route('/services')
def services():
    return 'Services'
@app.route('/about')
def about():
    return 'About'

# 相对projects解释相似于文件夹解释形式,指向某一个文件夹下的某个文件
@app.route('/projects/')
@app.route('/projects_our') # 能够定义多个URL到同一个视图函数上,Flask支持
def projects():
    return 'Projects'

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

 动态路由

# 动态路由
@app.route('/user/<username>')
def user(username):
    print username
    return username

# 路由转换器:指定参数类型
# flask提供3种:int(整形)|float(浮点型)|path(路径,并支持一个/)
@app.route('/user/<int:user_id>')
def user(user_id):
    print user_id
    return 'User_id:%s'%user_id

 自定义路由规则

# flask不提供正则表达的形式的URL匹配
# 可经过定义完成
# 一、from werkzeug.routing import BaseConverter
# 二、自定义类
#转换器
class RegexConverter(BaseConverter):
    def __init__(self,url_map,*items):
        super(RegexConverter,self).__init__(self)
        # print items # (u'[a-z]{3}[A-Z]{3}',)
        # print url_map # URL 的一个MAP对象,相似路由表
        self.regex = items[0]

# 三、要将定义的类注册到APP的url_map中,定义名称
# app.url_map.converters['regex'] = RegexConverter

# 四、使用
@app.route('/user/<regex("[a-z]{3}[A-Z]{3}"):username>')
def user(username):
    print username
    return 'Username:%s' % username

 浅析源码

注册路由规则的时候,flask 内部作了哪些东西呢?咱们来看看 route 方法:ui

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.
    """

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

    return decorator
route

route 方法内部也是调用 add_url_rule,只不过在外面包了一层装饰器的逻辑,这也验证了上面两种方法等价的说法

def add_url_rule(self, rule, endpoint=None, view_func=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.
    """
        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.
        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
add_url_rule

上面这段代码省略了处理 endpoint 和构建 methods 的部分逻辑,能够看到它主要作的事情就是更新 self.url_mapself.view_functions 两个变量。找到变量的定义,发现 url_mapwerkzeug.routeing:Map 类的对象,rulewerkzeug.routing:Rule 类的对象,view_functions 就是一个字典。这和咱们以前预想的并不同,这里增长了 RuleMap 的封装,还把 urlview_func 保存到了不一样的地方。

须要注意的是:每一个视图函数的 endpoint 必须是不一样的,不然会报 AssertionError

未完待续。。。

相关文章
相关标签/搜索