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

时间:2014-05-07 22:46:43

标签: 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/而无需触及所有其他路由器。

这可能在烧瓶中,如果是这样,怎么样?

1 个答案:

答案 0 :(得分:3)

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

什么是转换器?

这就是让你像这样定义路线的魔力:

@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)

何时调用转换器?

当烧瓶与您的路线匹配时,需要填写转换器处理的斑点。因此,根据以下路线 - /find/<user:user>,我们的转换器会处理以下所有网址。

  1. /查找/ 1
  2. /查找/ 2
  3. /查找/雅伊梅苏拉
  4. /查找/ zasdf123
  5. 对于上面的url,使用'1','2','jaime'和'zasdf123'调用UserConverter.to_python方法。由方法确定值是否转换为有效用户。如果是,则将有效用户直接传递到路径的user参数。

    然而,烧瓶仍然需要知道关于您的新转换器。这很简单:

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

    自定义转换器的最后一个很酷的功能是它们使构建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>/)