Bottle Static files

35,472

Solution 1

As indicated in the documentation, you should serve static files using the static function and css is a static file. The static function handles security and some other function which you can find out from the source. The path argument to the static function should point to the directory wherever you store the css files

Solution 2

To serve static files using bottle you'll need to use the provided static_file function and add a few additional routes. The following routes direct the static file requests and ensure that only files with the correct file extension are accessed.

from bottle import get, static_file

# Static Routes
@get("/static/css/<filepath:re:.*\.css>")
def css(filepath):
    return static_file(filepath, root="static/css")

@get("/static/font/<filepath:re:.*\.(eot|otf|svg|ttf|woff|woff2?)>")
def font(filepath):
    return static_file(filepath, root="static/font")

@get("/static/img/<filepath:re:.*\.(jpg|png|gif|ico|svg)>")
def img(filepath):
    return static_file(filepath, root="static/img")

@get("/static/js/<filepath:re:.*\.js>")
def js(filepath):
    return static_file(filepath, root="static/js")

Now in your html, you can reference a file like so:

<link type="text/css" href="/static/css/main.css" rel="stylesheet">

Directory layout:

`--static
|  `--css
|  `--fonts
|  `--img
|  `--js

Solution 3

Just providing an answer here because a number of my students have used this code in an assignment and I have a bit of a concern about the solution.

The standard way to serve static files in Bottle is in the documentation:

from bottle import static_file
@route('/static/<filepath:path>')
def server_static(filepath):
    return static_file(filepath, root='/path/to/your/static/files')

in this way, all of the files below your static folder are served from a URL starting with /static. In your HTML, you need to reference the full URL path for the resource, eg:

<link rel='stylesheet' type='text/css' href='/static/css/style.css'>

The answer from Sanketh makes it so that any reference to an image, css file etc anywhere in the URL space is served from a given folder inside the static folder. So /foo/bar/baz/picture.jpg and /picture.jpg would both be served from static/images/picture.jpg. This means that you don't need to worry about getting the path right in your HTML code and you can always use relative filenames (ie. just src="picture.jpg").

The problem with this approach comes when you try to deploy your application. In a production environment you want the static resources to be served by a web server like nginx, not by your Bottle application. To enable this, they should all be served from a single part of the URL space, eg. /static. If your code is littered with relative filenames, it won't translate easily to this model.

So, I'd advise using the three line solution from the Bottle tutorial rather than the more complex solution listed on this page. It's simpler code (so less likely to be buggy) and it allows you to seamlessly move to a production environment without code changes.

Solution 4

Rather than use regular expression matching for serving files as in Sanketh's answer, I'd prefer not to modify my templates and provide a path to the static files explicitly, as in:

<script src="{{ get_url('static', filename='js/bootstrap.min.js') }}"></script>

You can do this simply by replacing the <filename> in the static route decorator with one of type :path - like so:

@app.route('/static/<filename:path>', name='static')
def serve_static(filename):
    return static_file(filename, root=config.STATIC_PATH)

The :path matches an entire file path in a non-greedy way so you don't have to worry about changing templates when switching to production - just keep everything in the same relative folder structure.

Solution 5

I've used Sanketh's template in the past but over time condensed it to an extension agnostic function. You just have to add extension-folder mappings in the ext_map dictionary. It defaults to static/ folder if an extension is not mapped explicitly.

import os.path    

# Static Routes
@get('/<filename>')
def serve_static_file(filename):
    ext = os.path.splitext(filename)[1][1:]
    ext_map = {'image':['png','gif','jpg','ico'],'js':['js']}
    sub_folder = next((k for k, v in ext_map.items() if ext in v),'')
    return static_file(filename, root='static/'+sub_folder)
Share:
35,472
IT Ninja
Author by

IT Ninja

\\\******__******///-----| |\ | ------- |\ | --------- /\ \\***** || *****//------| | \ | | | \ | | / \ \*|====||====|*/-------| | \ | | | \ | | / \ /***** || *****\-------| | \ | | | \ | | /------\ //***** || *****\\------| | \ | | | \ | | / \ ///***** || *****\\\-----| | \ | | | \ | \ / / \ ////***** TT *****\\\\----| | \| ------- | \| \__/ / \ -------------------------------------------------------------------------------- Familiar Langauges: || C, C++, Ruby, Python, Javascript, Java, Coffeescript, || SQL(Postgres, sqlite3) Frameworks: || Ruby on Rails, Twitter Bootstrap, Django, Bottle, ... || || || -------------------------------------------------------------------------------- Best quotes from Stack Overflow: "Assume you are running on the Death Station 9000, a machine whose primary operating system allocates memory from the brains of kittens, and only puts it back if told to do so explicitly. Also, any instance of undefined behaviour will result in the destruction of the Earth." -- Stack Overflow User

Updated on May 16, 2020

Comments

  • IT Ninja
    IT Ninja about 4 years

    I have tried reading the docs for Bottle, however, I am still unsure about how static file serving works. I have an index.tpl file, and within it it has a css file attached to it, and it works. However, I was reading that Bottle does not automatically serve css files, which can't be true if the page loads correctly.

    I have, however, run into speed issues when requesting the page. Is that because I didn't use the return static_file(params go here)? If someone could clear up how they work, and how they are used when loading the page, it would be great.

    Server code:

    from Bottle import route,run,template,request,static_file
    
    
    
    @route('/')
    def home():
        return template('Templates/index',name=request.environ.get('REMOTE_ADDR'))
    
    run(host='Work-PC',port=9999,debug=True)
    

    Index:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
      <meta http-equiv="content-type"
     content="text/html; charset=ISO-8859-1">
      <title>index</title>
      <link type="text/css"
     href="cssfiles/mainpagecss.css"
     rel="stylesheet">
    </head>
    <body>
    <table
     style="width: 100%; text-align: left; margin-left: auto; margin-right: auto;"
     border="0" cellpadding="2" cellspacing="2">
      <tbody>
        <tr>
          <td>
          <h1><span class="headertext">
          <center>Network
    Website</center>
          </span></h1>
          </td>
        </tr>
      </tbody>
    </table>
    %if name!='none':
        <p align="right">signed in as: {{name}}</p>
    %else:
        pass
    %end
    <br>
    <table style="text-align: left; width: 100%;" border="0" cellpadding="2"
     cellspacing="2">
      <tbody>
        <tr>
          <td>
          <table style="text-align: left; width: 100%;" border="0"
     cellpadding="2" cellspacing="2">
            <tbody>
              <tr>
                <td style="width: 15%; vertical-align: top;">
                <table style="text-align: left; width: 100%;" border="1"
     cellpadding="2" cellspacing="2">
                  <tbody>
                    <tr>
                      <td>Home<br>
                      <span class="important">Teamspeak Download</span><br>
                      <span class="important">Teamspeak Information</span></td>
                    </tr>
                  </tbody>
                </table>
                </td>
                <td style="vertical-align: top;">
                <table style="text-align: left; width: 100%;" border="1"
     cellpadding="2" cellspacing="2">
                  <tbody>
                    <tr>
                      <td>
                      <h1><span style="font-weight: bold;">Network Website</span></h1>
    To find all of the needed information relating to the network's social
    capabilities, please refer to the links in the side bar.</td>
                    </tr>
                  </tbody>
                </table>
                </td>
              </tr>
            </tbody>
          </table>
          </td>
        </tr>
      </tbody>
    </table>
    </body>
    </html>