Flask中添加自定义转换器(Converter)

目录

Flask 提供的测试服务器对静态文件支持不佳,解析网页的路由与静态文件的路径冲突。 在生产环境中,使用 Ngnix 等服务器都支持静态文件,所以可以用生产环境的静态文件 url 代替开发环境的 url。
或者,可以为静态文件配置单独的控制器,使用 send_from_directory 等函数返回文件。
我尝试使用下面的两个路由设置,没成功。

@app.route('/static/<path:path>')
...
@app.route('/<owner>/<repo>/<path:path>')
...

解析 /static/app/index.js 文件失败,使用第二个路由(位置问题?有时间再试)。
Stackoverflow 上的一个回答给出几种解决方法,其中一种方法使用自定义的转换器(Converter)来设置路由匹配。

Converter

转换器对路由路径中参数进行限定,比如 int 表示接受 int 型的路径参数,上面的路由中的 path 也是一种转换器,接受包括斜杠 (/) 的字符串,通常用于路由匹配表达式的最后。
Flask 的转换器 (Converter) 来自 werkzeug 库,该库还提供自定义转换器的功能。 下面我就利用自定义一个转换器来区分静态文件和非静态文件。

Converter 说明

下面是一个来自 werkzeug 库的自定义 Converter 实例。网址

from random import randrange
from werkzeug.routing import Rule, Map, BaseConverter, ValidationError


class BooleanConverter(BaseConverter):
    def __init__(self, url_map, randomify=False):
        super(BooleanConverter, self).__init__(url_map)
        self.randomify = randomify
        self.regex = '(?:yes|no|maybe)'

    def to_python(self, value):
        if value == 'maybe':
            if self.randomify:
                return not randrange(2)
            raise ValidationError()
        return value == 'yes'

    def to_url(self, value):
        return value and 'yes' or 'no'

自定义的 Converter 需要至少定义两个方法:to_pythonto_url
to_python 用于将 URL 中的路径转换为 Python 对象,传递给 view 函数。
to_url 则由 url_for 调用,将参数转换为 URL 中合适的形式。

识别静态文件的 Converter

从上面的描述很容易能分析出,识别静态文件的 Converter 需要在 to_python 函数中判断当前路径是否属于静态文件。 而我的静态文件都放在 static 文件加下,所以只需要检查第一个参数是否为 static 即可。
我创建一个叫 none_static 的转换器,当路径属于静态文件时,匹配失败。代码如下

class NoStaticConverter(BaseConverter):
    def to_python(self, value):
        if value == 'static':
            raise ValidationError()
        return value
    def to_url(self, value):
        return str(value)

将上面的路由改为

@app.route('/<no_static:owner>/<repo>')
...

该条路由就不会再匹配静态文件了。