2
votes

I am making a website using Flask. It's utilizing a base template in HTML, which is used for all pages. In the base page (called base.html) there is some references to various static files. The references are using relative paths.

Here is a couple of examples from base.html:

<link rel="stylesheet" href="../static/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="../static/css/main.css">

This works fine, as long as I don't include input parameters in my route, but rather get them from requests like this:

@app.route('/person/delete')
def delete_person():
    id = request.args.get('id')
    # some more logic here...

However, if I change my route to include the input parameters, like this:

@app.route('/person/delete/<int:id>')
def delete_person(id):
    # some more logic here...

Then my relative path will fail. It seems that I am one level to deep, in the latter example. At least I get the following error in the log:

127.0.0.1 - - [29/Dec/2019 19:20:14] "GET /person/static/css/bootstrap-theme.min.css HTTP/1.1" 404 -
127.0.0.1 - - [29/Dec/2019 19:20:14] "GET /person/static/css/main.css HTTP/1.1" 404 -

The person part should not be a part of the URL, as the static folder is in the root level. Is there some clever way to counter this behavior?

Note: I could probably avoid relative paths in the base.html file and simply use some sort of shortcut to the base folder, but that would potentially mean that I can never use relative paths. That would be quite sad.

1
You need to use url_for - roganjosh
Does this answer your question? Create dynamic URLs in Flask with url_for() - roganjosh
../static seems wrong to me, it wouldn't be /static ? - geckos
@roganjosh I though url_for() was just an alternative to a string url (similar to nameof() in C#). Does it behave differently than writing the url? - Jakob Busk Sørensen

1 Answers

3
votes

As mentioned in comments, url_for is the proper solution.

An example from other project:

<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='nnn.min.css') }}">

In general, url_for cannot be replaced by hardcoded URLs, not even absolute ones, because the whole Flask application may be deployed with a prefix in its base URL, e.g. https://www.example.com/appname. The appname is a part of the configuration and it is known only at runtime.