'Firefox or Chrome can't find a photo inserted in a Bottle template

I am old timer but young learner. I want make my own website, using Python and Bottle. I have an HTML page which contains a title, a subtitle and a photo. This is a template used by Bottle in this little code:

from bottle import route, run, view
 
@route("/")
@view("pagedegarde.html")
def menu() :
    contenu = "Moto de l'abbé Khan"
    return {"titre" : "Bécanes", "contenu" : contenu}
 
run(host = '0.0.0.0', port  = 8080, debug = True, reloader = True)

Here is the template, "gardepage.html":

<!doctype html>
<!-- page_de_garde.tpl -->
<HTML lang="fr">
  <HEAD>
     <TITLE>{{titre}}</TITLE>
     <meta charset="UTF-8">
  </HEAD>
 
  <body>
    <header>
    <h1>Phrases et attrapes</h1>
    </header>
    <h3>{{titre}}</h3>
    <p><image src="turquoise.jpg" alt="125 k4" /></p>
    {{!contenu}}
    <hr/>
  </body>
</html>

The photo is in the same directory as the template and the python file.

Results :

127.0.0.1 - - [13/Mar/2022 11:10:58] "GET /turquoise.jpg HTTP/1.1" 404 746

The page is displayed, the title, the subtitle, but not the photo, there is instead the alternative mention "125 k4".

I wonder what it is, "746". Since I've had so many 404s (!), I've found that terminal messages always follow "404" with another number. I tried to find out about it, but couldn't find anything.

Otherwise, if I click on the html file, it displays without a problem, including the photo.

I tried both suffixes .tpl or .html, there is no difference. I tried .png or .jpg : no difference. And I get the same result with Python 3.8.1 and Bottle 0.12.7 or with Python 3.10.2 and Bottle 0.12.19. Thanks for reading me.



Solution 1:[1]

Bottle doesn't serve image/js/css automatically - you have to add own function for this.

It is simpler if you put static files in subfolder because then function can recognize this folder in url and run correct function. And this is popular method in other frameworks.

See: Routing Static Files

Example uses subfolder static for this - so you should have files

main.py
pagedegarde.html
static/turquoise.jpg
from bottle import route, run, view, static_file
 
@route("/")
@view("pagedegarde.html")
def menu() :
    contenu = "Moto de l'abbé Khan"
    return {"titre" : "Bécanes", "contenu" : contenu}
 
@route('/static/<filepath:path>')
def server_static(filepath):
    return static_file(filepath, root='static/')
    # or with full path
    #return static_file(filepath, root='/full/path/to/static/')

run(host='0.0.0.0', port=8080, debug=True, reloader=True)

And remember to use /static in HTML

<p><image src="/static/turquoise.jpg" alt="125 k4" /></p>

Other frameworks may have the same problem. Some may serve static file only in debug mode but in normal mode they should be executed with web servers like Apache or nginx which should serve static files (because they do this faster)


EDIT:

To serve image in the same folder you would need to use regex to recognize filename in URL

@route('<filepath:re:.*\.(jpg|png|gif)>')
def server_static(filepath):
    return static_file(filepath, root='')

The same you would have to do for other static files .css, .js, etc.

And if you would like to server other files for downloading or displaying then you would have to add also other extensions - ie. .csv, .xls, .mov, .mp3, etc.


If you would use regex .* as last route then it would serve all files (which don't match to previous routes)

@route('<filepath:re:.*>')
def server_static(filepath):
    return static_file(filepath, root='')

but it is not safe because someone could run ie. http://0.0.0.0:8080/main.py to download source code.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1