Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set static_url_path in Flask application

Tags:

flask

I want to do something like this:

app = Flask(__name__)
app.config.from_object(mypackage.config)
app.static_url_path = app.config['PREFIX']+"/static"

when I try:

print app.static_url_path

I get the correct static_url_path

But in my templates when I use url_for('static'), The html file generated using jinja2 still has the default static URL path /static with the missing PREFIX that I added.

If I hardcode the path like this:

app = Flask(__name__, static_url_path='PREFIX/static')

It works fine. What am I doing wrong?

like image 919
user3873617 Avatar asked Nov 03 '14 20:11

user3873617


3 Answers

Just to complete the answer above, we also need to clear the view_functions that maps the endpoint with the delegate:

app.view_functions["static"] = None
like image 156
Chomarat Julien Avatar answered Oct 20 '22 21:10

Chomarat Julien


The accepted answer is correct, but slightly incomplete. It is true that in order to change the static_url_path one must also update the app's url_map by removing the existing Rule for the static endpoint and adding a new Rule with the modified url path. However, one must also update the _rules_by_endpoint property on the url_map.

It is instructive to examine the add() method on the underlying Map in Werkzeug. In addition to adding a new Rule to its ._rules property, the Map also indexes the Rule by adding it to ._rules_by_endpoint. This latter mapping is what is used when you call app.url_map.iter_rules('static'). It is also what is used by Flask's url_for().

Here is a working example of how to completely rewrite the static_url_path, even if it was set in the Flask app constructor.

app = Flask(__name__, static_url_path='/some/static/path')

a_new_static_path = '/some/other/path'

# Set the static_url_path property.
app.static_url_path = a_new_static_path

# Remove the old rule from Map._rules.
for rule in app.url_map.iter_rules('static'):
    app.url_map._rules.remove(rule)  # There is probably only one.

# Remove the old rule from Map._rules_by_endpoint. In this case we can just 
# start fresh.
app.url_map._rules_by_endpoint['static'] = []  

# Add the updated rule.
app.add_url_rule(f'{a_new_static_path}/<path:filename>',
                 endpoint='static',
                 view_func=app.send_static_file)

like image 40
Erick Peirson Avatar answered Oct 20 '22 21:10

Erick Peirson


Flask creates the URL route when you create the Flask() object. You'll need to re-add that route:

# remove old static map
url_map = app.url_map
try:
    for rule in url_map.iter_rules('static'):
        url_map._rules.remove(rule)
except ValueError;
    # no static view was created yet
    pass

# register new; the same view function is used
app.add_url_rule(
    app.static_url_path + '/<path:filename>',
    endpoint='static', view_func=app.send_static_file)

It'll be easier just to configure your Flask() object with the correct static URL path.

Demo:

>>> from flask import Flask
>>> app = Flask(__name__)
>>> app.url_map
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
>>> app.static_url_path = '/PREFIX/static'
>>> url_map = app.url_map
>>> for rule in url_map.iter_rules('static'):
...     url_map._rules.remove(rule)
... 
>>> app.add_url_rule(
...     app.static_url_path + '/<path:filename>',
...     endpoint='static', view_func=app.send_static_file)
>>> app.url_map
Map([<Rule '/PREFIX/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
like image 11
Martijn Pieters Avatar answered Oct 20 '22 23:10

Martijn Pieters