Flask 路由层 配置文件

Flask的路由是基于装饰器实现的,其本质是通过app.add_url_rule方法实现的

来看下面函数与路由在源码中的流程

from flask import Flask
app = Flask(__name__)

# 这里要注意: route加括号已经执行了 
@app.route('/', methods=['GET', 'POST'], endpoint='haha')  --> 已经变成: @decorator
def hello_world():
    return 'Hello World!'

源码

    route源码:
    def route(self, rule, **options):  self是Flask对象 即app, rule是我们写的路由, options是其余参数组成的字典
        def decorator(f):  f是视图函数
            endpoint = options.pop("endpoint", None)  拿到别名并将别名从options字典中删除
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

    add_url_rule源码:
    @setupmethod
    def add_url_rule(
        self,  # --> Flask对象,即app
        rule,  # --> 装饰器里的路由
        endpoint=None,  # --> 路由别名
        view_func=None,  # --> 视图函数
        provide_automatic_options=None,
        **options  # 用来接收methods等参数的字典
    ):
        
        if endpoint is None:  # 若路由没有起别名          
            endpoint = _endpoint_from_view_func(view_func)  # endpoint = 视图函数的名字
        options["endpoint"] = endpoint  # 将endpoint添加到options里
        methods = options.pop("methods", None)  # 获取methods的值

        if methods is None:  
            # methods为空 则默认是GET请求
            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)

        required_methods = set(getattr(view_func, "required_methods", ()))

        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

        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)  # 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
                )
            # 若view_functions中有endpoint 则取出赋值给view_func
            # view_func要么必须有值, 要么endpoint有别名, 最终endpoint的值也会赋值给view_func
            self.view_functions[endpoint] = view_func  
            # 如果endpoint有别名 view_func = endpoint
            # 如果endpoint没有有别名 view_func = endpoint(视图函数名字)

核心源码: route -> decorator -> add_url_rule
flask路由基于装饰器,本质是基于:add_url_rule
add_url_rule 源码中,endpoint如果为空,
endpoint = _endpoint_from_view_func(view_func),最终取view_func.__name__(函数名)

  • @app.route('/user/<username>')
  • @app.route('/post/<int:post_id>')
  • @app.route('/post/<float:post_id>')
  • @app.route('/post/<path:path>')

常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:

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

路由的两种写法

  • 典型装饰器写法
from flask import Flask
app = Flask(__name__)

# 路由装饰器配置该函数的路由
@app.route('/index/<int:nid>',methods=['GET'],endpoint='haha')
def index(nid):
    return str(nid)

路由参数:

'/index/<int:nid>'  : 路由有名分组,视图函数要接收
methods  : 该视图函数可以用的请求方式
endpoint  : 路由别名反向解析, 在其他视图函数中用: real_url=url_for("别名") 调用该函数
     endpoint默认指定的是函数名字

  • add_url_rule 写法
app.add_url_rule参数:
- rule, URL规则
- view_func, 视图函数名称
- defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}为函数提供参数
- endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
- methods = None, 允许的请求方式,如:["GET", "POST"]
- redirect_to = '/login'  重定向到指定的地址 可以是路径也可以是别名
- strict_slashes  严格模式
        @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

案例:

def index(nid):
    return nid

app.add_url_rule(
    '/index/<string:nid>',  # url
    view_func=index,  # 该路由关联的函数
    endpoint="haha",  # 路由别名
    methods=['POST',"GET"]  # 允许的请求方式
    )

补充: 别名使用

from flask import Flask, request, render_template, redirect, url_for
app = Flask(__name__)

# 路由装饰器配置该函数的路由
@app.route('/login/<string:nid>',methods=['GET'],endpoint='haha')
def login(nid):
    return render_template('login.html', nid=nid)

def index(nid):
    url = url_for('haha', nid=nid)  # 通过路由别名反向生成路由
    print(url)  # /login/1
    return redirect(url)  # 重定向到login路由对应的函数
app.add_url_rule('/index/<string:nid>',view_func=index,methods=['POST',"GET"])


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

补充: 反向生成路由时也可以携带参数

注意: 别名不能重复,一个路由一个别名

路由扩展 支持正则

Flask路由默认不支持正则匹配,我们可以自定义路由扩展使其支持正则:

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

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

from werkzeug.routing import BaseConverter

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

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        """
        #value就正则匹配出来的结果
        # print('value',value,type(value))
        return value

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        """
        val = super(RegexConverter, self).to_url(value)
        # print(val)  # 666
        return val

app.url_map.converters['regex'] = RegexConverter
@app.route('/test/<regex("\d+"):nid>',endpoint="tes")
def test(nid):
    print("nid",nid,type(nid))
    print(url_for('tes', nid='666'))  # /test/666
    return 'test'

配置文件

方式一:

这中方式只能配置两种:
app.debug=True
app.secret_key="123123"

方式二:

使用config字典:
app.config['DEBUG']=True

方式三:

导入文件(插拔式) ,推荐使用

  • settings.py
class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'


class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'


class DevelopmentConfig(Config):
    DEBUG = True


class TestingConfig(Config):
    TESTING = True
  • 视图函数文件.py
from flask import Flask

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')

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

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

补充:

flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:

{
        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
        'TESTING':                              False,                          是否开启测试模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值