python - Flask 多个 URL 处理程序部分处理 URL

标签 python url routes flask flask-restful

是否可以在flask中定义url路由器来处理url的特定部分并将url传递给下一个url处理程序以进一步处理?

用例是 url 中重复很多且始终需要相同处理的静态部分。 /user/1/something

/user/1/something-else

/user/2/...

理想情况下,处理程序将处理 /user/<id>部分(加载数据库记录等)并将结果存储到本地上下文。然后另一个处理程序将处理剩余的 url。这将使我能够替换 user部分(例如 /user/<name/ 而不触及所有其他路由器。

这在 flask 中可能吗?如果可以,如何实现?

最佳答案

我不确定你能做你想做的事。但是,从您上面描述的用法来看,我认为您只需要一个转换器。

什么是转换器?

正是这种魔力让你可以像这样定义路由:

@app.route('/double/<int:number>')
def double(number):
    return '%d' % (number * 2)

上面,路由只接受/double/ints 。更好的是,url 部分中传递的任何内容都会转换为 int。因此,转换器绰号:D。

转换器遵循<converter:variable_name>格式。您可以阅读 Flask 内置转换器 here .

关于转换器的最好的部分是您可以编写自己的自定义数据类型!为此,只需从 werkzeug.routing.BaseConverter 派生即可并填写to_python和to_url。下面,我为无处不在的 User 对象创建了一个简单的转换器。

class UserConverter(BaseConverter):
    """Converts Users for flask URLs."""

    def to_python(self, value):
        """Called to convert a `value` to its python equivalent.

        Here, we convert `value` to a User.
        """
        # Anytime an invalid value is provided, raise ValidationError.  Flask
        # will catch this, and continue searching the other routes.  First,
        # check that value is an integer, if not there is no way it could be
        # a user.
        if not value.isdigit():
            raise ValidationError()
        user_id = int(value)

        # Look up the user in the database.
        if user_id not in _database:
            raise ValidationError()

        # Otherwise, return the user.
        return _database[user_id]

    def to_url(self, value):
        """Called to convert a `value` to its `url` equivalent.

        Here we convert `value`, the User object to an integer - the user id.
        """
        return str(value.id)

转换器何时被调用?

当 Flask 与您的路线匹配并且需要填充转换器处理的点时。因此,给出以下路线 - /find/<user:user> ,以下所有 URL 均由我们的转换器处理。

  1. /查找/1
  2. /查找/2
  3. /查找/jaime
  4. /find/zasdf123

对于上面的 url,使用“1”、“2”、“jaime”和“zasdf123”调用 UserConverter.to_python 方法。由该方法来确定这些值是否转化为有效用户。如果是这样,则有效用户将直接传递到路由的 user参数。

但是,flask 仍然需要了解您的新转换器。这很简单:

app.url_map.converters['user'] = UserConverter

自定义转换器的最后一个很酷的功能是它们使构建 URL 成为一个自然、简单的过程。要创建 url,只需执行以下操作:

url_for('find_user', user=user)

最后,一个简单的程序将所有这些结合在一起。

from flask import Flask, url_for
from werkzeug.routing import BaseConverter, ValidationError


class User:

    def __init__(self, id, name):
        self.id = id
        self.name = name


class UserConverter(BaseConverter):
    """Converts Users for flask URLs."""

    def to_python(self, value):
        """Called to convert a `value` to its python equivalent.

        Here, we convert `value` to a User.
        """
        # Anytime an invalid value is provided, raise ValidationError.  Flask
        # will catch this, and continue searching the other routes.  First,
        # check that value is an integer, if not there is no way it could be
        # a user.
        if not value.isdigit():
            raise ValidationError()
        user_id = int(value)

        # Look up the user in the database.
        if user_id not in _database:
            raise ValidationError()

        # Otherwise, return the user.
        return _database[user_id]

    def to_url(self, value):
        """Called to convert a `value` to its `url` equivalent.

        Here we convert `value`, the User object to an integer - the user id.
        """
        return str(value.id)


# Create a `database` of users.
_database = {
    1: User(1, 'Bob'),
    2: User(2, 'Jim'),
    3: User(3, 'Ben')
}

app = Flask(__name__)
app.url_map.converters['user'] = UserConverter

@app.route('/find/<user:user>')
def find_user(user):
    return "User: %s" % user.name

@app.route('/find/<user:user>/extrapath')
def find_userextra(user):
    return 'User extra: %s' % user.name

@app.route('/users')
def list_users():
    # Return some broken HTML showing url's to our users.
    s = ''
    for user in _database.values():
        s += url_for('find_user', user=user) + '<br/>'
    return s

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

如果有什么不清楚,或者喘气存在错误,请告诉我:D。这适用于您的问题,因为您提到了一系列以相同开头的网址 -

/user/1/something

/user/1/something-else

/user/2/

对于这些路由,您可以应用自定义转换器,如下所示:

@app.route('/user/<user:user>/something')

@app.route('/user/<user:user>/something-else')

@app.route('/user/<user:user>/)

关于python - Flask 多个 URL 处理程序部分处理 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23529785/

相关文章:

php - 通过标签中包含空格的标签获取 YouTube 视频源

PHP路由: display flash messages in View (Klein)

ruby-on-rails - 将静态页面部署到域根并将rails应用程序部署到子域

python - python CNTK 中损失函数的替代方案

Python for 循环范围内的增强算术

python - 如何使用 django.views.generic.date_based.archive_index 获取前五个对象?

Python turtle 井字游戏

c# - .NET:使用 C# 列出 HTTP 流量 URL

java - 我正在尝试使用 Socket 连接到 URL,但只能通过提供 IP 地址(Java android)进行连接

ruby-on-rails - Rails - 基于路由名称的路由重定向