如何在规则映射到端点之前处理Flask中的URL?

时间:2016-02-19 20:08:47

标签: python flask werkzeug

我正在尝试在我的API中实现一个功能,其中一部分URL是可选的。如果提供,我想处理它并在g中粘贴一些数据。如果没有,我会在g中添加一些默认信息。无论哪种方式,我都会在规则映射到端点之前将其从URL中删除。所以我希望以下两个URL最终调用相同的端点:

/bar/1   (I would fill in a default value for foo here)
/foo/32/bar/1

我想在每个端点都有相同的可选URL。我想我可以通过装饰每个端点来蛮力地做到这一点,但我有超过250个,所以我想要更优雅的东西。

我正在使用多个蓝图,如果可能的话,我希望让每个端点尽可能简单(蓝图已经有了自己的前缀):

@blueprint1.route('/bar/<int:id>', methods=['GET'])
@blueprint2.route('/bar/<int:id>', methods=['GET'])
def get_foo():

我已经尝试了@url_defaults,@ url_value_preprocessor和@before_request装饰器,但似乎规则已经映射到端点了。在映射完成之前是否有钩子来访问URL?

2 个答案:

答案 0 :(得分:2)

我通过继承Flask类并重写create_url_adapter()函数来完成这项工作,如下所示:

class MyFlask(Flask):
    """
    MyFlask subclasses the standard Flask app class so that I can hook the URL parsing before the URL
    is mapped to a Route. We do this so we can extract an optional "/foo/<int:foo_id>" prefix. If we
    see this prefix, we store the int value for later processing and delete the prefix from the URL before
    Flask maps it to a route.
    """

def _extract_optional_foo_id(self, path):
    ....
    return path, foo_id  # path has the optional part removed

def create_url_adapter(self, request):
        """
        Augment the base class's implementation of create_url_adapter() by extracting an optional foo_id and modifying
        the URL. The Flask function name is misleading: we aren't creating anything like an object. The "adapter" is
        just this function call. We add our own behavior then call the super class's version of this function.
        :param request: Flask's Request object
        :return: the results of the Flask super class's create_url_adapter()
        """
        # Must test for request. It is None when calling this for the app-wide scenario (instead of request-wide).
        if request and request.environ:
            (new_path, foo_id) = self._extract_optional_foo_id(request.environ['PATH_INFO'])
            if foo_id is not None:
                request.environ['PATH_INFO'] = new_path
                request.foo_id_in_url = foo_id

        return super(MyFlask, self).create_url_adapter(request)

然后在我的应用程序初始化代码中,我执行:

,而不是实例化Flask的实例
app = MyFlask( ... )

答案 1 :(得分:0)

通常,URL在应用程序初始化期间仅映射到端点一次。更确切地说 - 每次解释器第一次遇到代码@app.route('/some_route') ...时。了解将URL映射到端点并不是每个请求都会发生(例如,在PHP中),这一点非常重要。

向端点添加一些默认值的一种方法是覆盖

之一
Flask.route()
Flask.add_url_rule()
Blueprint.route()

在你的后继app / blueprint课程中。只需将其放入**options dict。