Flask: Static files in subdirectories

16,338

Dont set the script name to a blank string, try setting it to '/projects/test'. By setting SCRIPT_NAME to a blank string the application thinks its running on the root of the domain, so routes generated by url_for will start there. With a script name of '/projects/test', url_for('static', filename='/foo/bar.css') will return '/projects/test/static/foo/bar.css'

If you genuinely want your apps static media served on a different endpoint then you'll just have to roll it yourself, something like this:

from flask import Flask
from os.path import join

app = Flask(__name__)

def url_for_static(filename):
    root = app.config.get('STATIC_ROOT', '')
    return join(root, filename)
Share:
16,338
Jonas Gröger
Author by

Jonas Gröger

Hello! I'm Jonas and work mainly as a backend software engineer (JVM languages, Python). I heard sometimes people see me working on frontend-y things aswell :)

Updated on June 04, 2022

Comments

  • Jonas Gröger
    Jonas Gröger about 2 years

    In my flask template file I include a css file (I ommited the boilerplate) like this:

    url_for('static', filename='css/bootstrap.css')

    This renders to /static/css/bootstrap.css which means (because of leading slash) it is interpreted as domain.com/static/css/boostrap.css. Unfortunately the actual static folder is located a subdirectory: domain.com/projects/test/static/

    Environment specifics:

    My fcgi file located in the ~/fcgi-bin folder (host specific i guess):

    $ cat ~/fcgi-bin/test.fcgi
    #!/usr/bin/env python2.7
    
    import sys
    sys.path.insert(0, "/home/abcc/html/projects/test")
    
    from flup.server.fcgi import WSGIServer
    from app import app
    
    class ScriptNameStripper(object):
       def __init__(self, app):
           self.app = app
    
       def __call__(self, environ, start_response):
           environ['SCRIPT_NAME'] = ''
           return self.app(environ, start_response)
    
    app = ScriptNameStripper(app)
    
    if __name__ == '__main__':
        WSGIServer(app).run()
    

    and my .htaccess located in domain.com/projects/test/

    $ cat .htaccess 
    <IfModule mod_fcgid.c>
       AddHandler fcgid-script .fcgi
       <Files ~ (\.fcgi)>
           SetHandler fcgid-script
           Options +FollowSymLinks +ExecCGI
       </Files>
    </IfModule>
    
    <IfModule mod_rewrite.c>
       Options +FollowSymlinks
       RewriteEngine On
       RewriteCond %{REQUEST_FILENAME} !-f
       RewriteRule ^(.*)$ /fcgi-bin/test.fcgi/$1 [QSA,L]
    </IfModule>
    

    To sum it up I want url_for('static', filename='css/bootstrap.css') to return static/css/bootstrap.css instead of /static/css/bootstrap.css

    EDIT #1

    I have noticed this happens also on normal url_for calls not for static files like url_for('about').

    EDIT #2

    I have written a quickstart-app and a blog post about this.

  • beep_check
    beep_check almost 4 years
    you can get the static folder path with: url_for('static', filename='')