Flask 的 url 处理器

前言

关于 url 处理器这个概念早在 Flask 0.7 版本就引入进去了,这是个很实用功能,这一次我们通过一个例子,感受一下 URL Processors 的实用之处.

如果有想学习python的程序员,可来我的python学习扣qun:711944363,免费送python的视频教程噢!我每晚上8点还会在群内直播讲解python知识,欢迎大家前来学习哦

 

例子

现在对于一个网站进行 i18n 化很重要,我们现在需要根据不同的语言然后获取不同的配置参数去配置我们的网站,标题导航栏,等等。那么如果让我们对原来下面的路由进行设置,应该怎么设计呢?

/post/<post_title>
/posts
# etc ...

很容易也很简洁的一个方案就是直接在 url 上加上语言变量 lang,像这样

/<lang>/post/<post_title>
/<lang>/posts

ok,url 重新设计完成了,让我们简单写一下路由函数

from flask import Flask,g,jsonify

app = Flask(__name__)

@app.route('/<lang>/post/<post_title>')
def index(lang,post_title):
    config = get_website_config_by_lang(lang)
    return jsonify({"config":g.config,"title":post_title})

@app.route('/<lang>/posts')
def posts(lang):
    config = get_website_config_by_lang(lang)
    return jsonify({"config":g.config,"list":[1,2,3]})

def get_website_config_by_lang(lang):
    if lang == 'eng':
        return {"lang":"eng","title":"Peach"}
    if lang == 'zh':
        return {"lang":"zh","title":"桃子"}

现在问题来了,我们现在只有两个路由,每个路由里都需要根据 url 的 lang 去获取配置,那要是 20 个或者更多呢? 都这样子写就多出来冗余代码,那么有没有更好的办法呢?答案是肯定的,解决方法就是 url_value_processor

url_value_processor

url_value_processor 是做什么的呢?看一下官方定义

Register a URL value preprocessor function for all view functions in the application. These functions will be called before the before_request() functions. 
The function can modify the values captured from the matched url before they are passed to the view. The function is passed the endpoint name and values dict. The return value is ignored.

如官方文档说的那样,它可以在返回视图前,修改匹配到的 url 的 value 值,具体是什么样子,让我们接着看下去

使用方法

让我们试着用 url_value_processor 去改造我们的代码

from flask import Flask,g,redirect,url_for,jsonify

app = Flask(__name__)

@app.url_value_preprocessor
def pull_lang_config(endpoint,values):
    lang = values.pop('lang',None)
    if lang:
        g.config = get_website_config_by_lang(lang)

@app.route('/<lang>/post/<post_title>')
def index(post_title):
    return jsonify({"config":g.config,"title":post_title})

@app.route('/<lang>/posts')
def posts():
    return jsonify({"config":g.config,"list":[1,2,3]})

@app.route('/<lang>/test') # 一个测试
def test():
    return redirect(url_for('posts'))

def get_website_config_by_lang(lang):
    if lang == 'eng':
        return {"lang":"eng","title":"Peach"}
    if lang == 'zh':
        return {"lang":"zh","title":"桃子"}

运行

尝试访问一下 /zh/post/test,看一下返回结果

{
  "config": {
    "lang": "zh", 
    "title": "\u6843\u5b50"
  }, 
  "title": "test"
}

再试一下 /eng/post/test:

{
  "config": {
    "lang": "eng", 
    "title": "Peach"
  }, 
  "title": "test"
}

其中 /<lang>/posts 结果也正常输出,等等,是不是忘了什么?让我们试一试 /<lang>/test,看一下输出结果:

werkzeug.routing.BuildError: Could not build url for endpoint 'posts'. Did you forget to specify values ['lang']?

好像报错了?这是为什么?因为我们在 url_value_preprocessor 的函数中把 lang 给从 values 出栈了,那么有没有解决办法呢?当然有的,往下看.

url_defaults

如果说 url_value_processor 是为了从 url 中取出相应的 value 值把它用到其他地方,那么 url_defaults 则是将其他地方的值重新放回到 url 中,如果不放回,一旦使用 url_for 就会出现上面的错误。

使用

让我们尝试在此改造上面的例子

from flask import Flask,jsonify,g, redirect,url_for

app = Flask(__name__)

@app.url_defaults
def add_lang(endpoint, values):
    values.setdefault("lang",g.lang)

@app.url_value_preprocessor
def pull_lang_config(endpoint,values):
    g.lang = values.pop('lang')
    g.config = get_website_config_by_lang(g.lang)

@app.route('/<lang>/post/<post_title>')
def index(post_title):
    return jsonify({"config":g.config,"title":post_title})

@app.route('/<lang>/posts')
def posts():
    return jsonify({"config":g.config,"list":[1,2,3]})

@app.route('/<lang>/test') # 一个测试
def test():
    return redirect(url_for('posts'))

def get_website_config_by_lang(lang):
    if lang == 'eng':
        return {"lang":"eng","title":"Peach"}
    if lang == 'zh':
        return {"lang":"zh","title":"桃子"}

运行

让我们直接测试 /<lang>/test 这个接口,看一下结果:

{
  "config": {
    "lang": "eng", 
    "title": "Peach"
  }, 
  "list": [
    1, 
    2, 
    3
  ]
}

大功告成

猜你喜欢

转载自blog.csdn.net/w17688977481/article/details/88713630
今日推荐