Flask 高级(转换器)

170 阅读4分钟

Flask 高级玩法

  进入高级部分,那么就必须有点正规军的样子吧,因此项目进行模块化拆分就显得很重要。为什么要模块化拆分呢?第一,模块化拆分使我们的项目结构更加清晰,每个模块各司其职,有自己单独的功能;第二,有利于后期对每个模块的管理维护。


  以下是我划分的模板结构,以后创建项目就不用再TMD的一个个文件单独去重复写了,直接到 application 下载基本模板,或者通过git向这个 flask-app-templates 地址进行克隆拉取。

项目模板结构划分如下:

|-- config.py
|-- manage.py
|-- __init__.py
|-- db
|   |-- db.py
|   |-- __init__.py
|-- static
|   |-- example.jpg
|-- templates
|   |-- admin.html
|   |-- index.html
|-- view
|   |-- admin.py
|   |-- public.py
|   |-- __init__.py

其中:

config.py:项目配置文件

manage.py:项目启动入口文件

__init__.py:此文件夹以python包的形式存在

db:数据库连接配置文件

static:静态资源目录(存放CSS、JavaScript、图片等)

templates:存放jinja模板的目录,HTML文件放这里

view:应用视图放这里(将蓝图存放在每个py文件中,做功能拆分)

转换器

转换器可以让我们自定义 url 规则。即 url 长什么样才能进入我们视图函数的处理。内置转换器有几个很简单的,点击传送门去看看?

由于内置转换器提供的都是很基本的转换器,通过正则的方式预先为我们定义好的,比如匹配数字的转换器,你不符合 url 某个部分是必须是数字的话,你就匹配不到我的视图函数...因此,我们需要对内置转换器进行自定义,通过正则定义规则,我们想要 url 长什么样就长什么样。下面开始介绍如何自定义转换器:

# 导入转换器的基类
from werkzeug.routing import BaseConverter

# 编写 URL 转换器
class RegexConverter(BaseConverter):
    """
    自定义 正则表达式匹配 URL 路由
    """

    def __init__(self, url_map, regex):
        super(RegexConverter, self).__init__(url_map)
        self.regex = regex

# 注册转换器 (蓝图中需要使用转换器,必须在蓝图值钱注册好)
app.url_map.converters['reg'] = RegexConverter

# 使用转换器
@public.route(r"/<reg('^1[358]\d{9}'):data>/", methods=['GET'])
def index(data):
  pass

先来说说转换器内部原理,相信你很快就明白转换器干的事情了。(这里不考虑其他细节,只考虑 url 与转换器的关系)

  • 首先假设浏览器地址栏发来一个 urlhttp://localhost/id/1234/ 的请求,然后用转换器对 url 进行匹配,前面路径相同的情况下,遍历到同一级路径下对 url 进行解析时,就会使用我们预定义好的 正则规则 去进行校验,如果符合则进入视图处理,不符合则没有对应的视图与之匹配。

  • 再来说说上面定义转换器的一些细节,比如注册转换器,里面的正则规则由我们在使用的时候根据需求进行临时定义 url 长什么样,这就很爽了对吧?那么,这个定义的正则表达式在进行路由匹配时,就会传递到定义转换器的regex 形参那里,也就是第二个参数,这个值就是flask之后用来匹配这层路径的规则。

  • 后面的data名称,是将来传递给视图函数的变量名。

  • 另外,如果正则表达式不想一遍一遍写,想在多个视图函数中直接使用,那么就可以在定义转换器时直接赋值,之后直接写转换器名,也就是注册时的名字,比如上面那个 reg 注册名,即转换器名。

class BaseConverter:
    """Base class for all converters."""

    regex = "[^/]+"

class IntegerConverter(NumberConverter):
    """This converter only accepts integer values::
        Rule("/page/<int:page>")
    """
    regex = r"\d+"
    # ...

比如这个内置的 int 转换器,他在里面重写了 转换器基类的 regex,然后自己定义好了 regex 的值了,就是要匹配数字的规则。所以之后在使用时,直接使用转换器名就行了。我们这里演示的是一个通用的方法,直接通过临时定义正则规则,然后传递到转换器的 regex 参数那里去供它使用。

有些人硬是抬杠了,为什么不是传递到第一个参数那里去呢?去看看官方源码就知道了,因为第一个参数是收集浏览器发送过来的整个 url 路径的值。最后上面的转换器规则终于算是讲完了 ^_^ 仔细捋一下,其实也挺简单鸭~~~

参考资料

[1]  werkzeug.palletsprojects.com/en/2.2.x/ro…

前端技术社群

我组建了一个氛围特别好的技术学习、交流社群,里面有很多技术大佬,如果你感兴趣的话(后续有计划也可以),我们可以一起进行前端技术相关的交流、学习、共建。下方加 皮蛋 好友回复『前端』即可。

relation.JPG 如果这觉得这篇内容对你有帮助,我想请你帮我2个小忙:

  1. 点个『在看』,让更多人也能看到这篇文章
  2. 订阅官方博客 https://juejin.cn/user/4341318265616215 让我们一起成长

点赞+在看,技术更棒