2

I'm struggling to find the proper way to setup my flask routes when moving my app to being hosted in a subdirectory. I've read a bunch of great answers on this subject, most notably this answer on adding a prefix to all routes. However, I think my situation is slightly different. I want to ONLY prefix the URLs I generate with url_for, not respond to those URLs. Is there a way to do this?

For example, assume my flask app is hosted at http://www.acme.com/tools/. The main acme.com domain is setup with a proxy pass to pass all requests from /tools/* to my app. So, my app only sees requests like /, /product_1/ even though the full URL is http://www.acme.com/tools/product_/, etc. So, my app.route rules can use / as the base route. The problem is I use url_for everywhere and I want the urls generated to be the full url like /tools/product_1, not /product_1. Is there a way to achieve this?

I've tried using blueprints but those will make the @app.route and url_for respond to /tools/xyz. Is there a more simple solution to this issue or is this a non-standard way to handle this issue?

Community
  • 1
  • 1
durden2.0
  • 9,222
  • 9
  • 44
  • 57

2 Answers2

1

I would take a look at this snippet: http://flask.pocoo.org/snippets/35/

I'm not sure I love the idea of modifying your WSGI environment as the only solution to this problem. You can always wrap url_for. (note that this won't work for _external=True)

def my_url_for(*args, **kwargs):
    return '/tools' + url_for(*args, **kwargs)

Be sure to set your APPLICATION_ROOT to /tools so that cookies are only accessible from the app.

Nick Frost
  • 490
  • 2
  • 12
  • I've considered wrapping `url_for` too. The downside though I have to pay careful attention to always use my wrapper instead of the regular function, which is confusing to contributors on the project. However, this might be the only good option. – durden2.0 Mar 18 '16 at 06:52
1

I found a different way to handle this without having to provide a wrapper for url_for. I'm using a custom routing rule to append the prefix. This means none of the app.route decorator calls have to be changed and all calls to url_for will automatically get the prefix added. Are there any caveats I'm missing by overriding the url_rule_class?

Add the following to your __init__.py after setting up your app.

from werkzeug.routing import Rule
class PrefixRule(Rule):
    def build(self, *args, **kwargs):
        domain_part, url = super(PrefixRule, self).build(*args, **kwargs)

        return domain_part, u'%s%s' % (app.config['PREFIX'], url)


app.url_rule_class = PrefixRule
durden2.0
  • 9,222
  • 9
  • 44
  • 57