MAE
MAE

Reputation: 39

Dynamically create Links from List in Flask

I am trying to dynamically create a list of links to files in a static folder and failing with nested {{ {{ }} }} that would be logically required.

A Flask server has files in

/Static/FileFolder

they are collected in a list with

FileList = []
    
for path in os.listdir(FileFolderPath):
    if os.path.isfile(os.path.join(FileFolderPath, path)):
        Filelist.append(path)

the Link is built with

return render_template('list.html', FileList = FileList)

and the Html has this piece

{% for item in FileList %}

<li><a href=" {{url_for('static', filename=' {{item}} ')  }}">{{item}}</a>  </li>

{% endfor %}

which fails as

filename=' {{item}} '

does not give me the url for the link to the file but just a nonsense link to

http://127.0.0.1:5020/static/%20%7B%7Bitem%7D%7D%20

which has the wrong folder and name. So how can i give the correct folder and place a link to a {{item}} inside a {{ }} used for url_for ?

Upvotes: 1

Views: 579

Answers (3)

Detlef
Detlef

Reputation: 8562

As already mentioned, you can pass the variable containing the relative path to the file directly without brackets and quotation marks.

Note that you need the full relative path inside the static folder to reference the file with url_for('static', filename=...) .

The following example uses the pathlib module to implement your requirements.

from pathlib import Path

@app.route('/')
def index():
    # ./static/path/to/folder/
    p = Path(app.static_folder, 'path', 'to', 'folder')
    filenames = [x.relative_to(app.static_folder) for x in p.iterdir() if x.is_file()]
    return render_template('index.html', **locals())
<ul>
    {% for filename in filenames -%}
    <li><a href="{{ url_for('static', filename=filename) }}">{{ filename }}</a></li>
    {% endfor -%}
</ul>

Upvotes: 1

Mircea Mesesan
Mircea Mesesan

Reputation: 41

What if you only use once the jinja2 markdown as it follows:

{% for link in links %}

        <li><a href="/static/{{ link }}">{{ link }}</a>  </li>

{% endfor %}

Another option, but this mainly depends on what you're trying to accomplish, is adding another route to your app.py

@app.route('/static/<page>')
def get_link(page):
    return f'{page}'

and afterwards in your html file:

<li><a href="{{ url_for('get_link', page=link) }}">{{ link }}</a></li>

Also, you might want to consider using the PEP8 naming guidelines > https://peps.python.org/pep-0008/#type-variable-names

Upvotes: 1

willwrighteng
willwrighteng

Reputation: 3002

You don't need the double curly braces inside a block that is already jinja templated

templates/lists.html

{% for item in FileList %}

<li><a href=" {{ url_for('file', variable=item)  }}">{{item}}</a>  </li>

{% endfor %}

app.py

import os
from flask import Flask, render_template


app = Flask(__name__)


def funk():
    FileList = []
    FileFolderPath = '.'

    for path in os.listdir(FileFolderPath):
        if os.path.isfile(os.path.join(FileFolderPath, path)):
            FileList.append(path)
    return FileList


@app.route('/')
def hello_world():
    FileList = funk()
    return render_template('./list.html', FileList = FileList)


@app.route('/<variable>/')
def file(variable):
    return variable

terminal

export FLASK_APP=app.py
flask run

tree

.
├── app.py
└── templates
    └── list.html

Upvotes: 1

Related Questions