Comment servir des fichiers statiques dans un flacon

donc c'est embarrassant. J'ai une application que j'ai créée dans Flask et pour l'instant il ne sert qu'une seule page HTML statique avec des liens vers CSS et JS. Et je ne trouve pas où dans la documentation Flask décrit le retour de fichiers statiques. Oui, je pourrais utiliser render_template mais je sais que les données ne sont pas templatisées. Je pensais que send_file ou url_for était la bonne chose, mais je n'ai pas pu les faire fonctionner. En attendant, je suis de l'ouverture de la fichiers, lecture de contenu, et montage d'un Response avec mimetype approprié:

import os.path

from flask import Flask, Response


app = Flask(__name__)
app.config.from_object(__name__)


def root_dir():  # pragma: no cover
    return os.path.abspath(os.path.dirname(__file__))


def get_file(filename):  # pragma: no cover
    try:
        src = os.path.join(root_dir(), filename)
        # Figure out how flask returns static files
        # Tried:
        # - render_template
        # - send_file
        # This should not be so non-obvious
        return open(src).read()
    except IOError as exc:
        return str(exc)


@app.route('/', methods=['GET'])
def metrics():  # pragma: no cover
    content = get_file('jenkins_analytics.html')
    return Response(content, mimetype="text/html")


@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def get_resource(path):  # pragma: no cover
    mimetypes = {
        ".css": "text/css",
        ".html": "text/html",
        ".js": "application/javascript",
    }
    complete_path = os.path.join(root_dir(), path)
    ext = os.path.splitext(path)[1]
    mimetype = mimetypes.get(ext, "text/html")
    content = get_file(complete_path)
    return Response(content, mimetype=mimetype)


if __name__ == '__main__':  # pragma: no cover
    app.run(port=80)

Quelqu'un veut donner un exemple de code ou une url pour cela? Je sais que cela va être simple.

320
demandé sur hughdbrown 2013-12-18 03:31:02

13 réponses

la méthode préférée est d'utiliser nginx ou un autre serveur web pour servir des fichiers statiques; ils seront en mesure de le faire plus efficacement que Flask.

cependant, vous pouvez utiliser send_from_directory pour envoyer des fichiers à partir d'un répertoire, ce qui peut être assez pratique dans certaines situations:

from flask import Flask, request, send_from_directory

# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

@app.route('/js/<path:path>')
def send_js(path):
    return send_from_directory('js', path)

if __name__ == "__main__":
    app.run()

Faire pas utiliser send_file ou send_static_file avec une fourni par l'utilisateur chemin.

send_static_file exemple:

from flask import Flask, request
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

@app.route('/')
def root():
    return app.send_static_file('index.html')
429
répondu atupal 2016-01-27 03:09:49

je suis sûr que vous trouverez ce dont vous avez besoin là: http://flask.pocoo.org/docs/quickstart/#static-files

fondamentalement, vous avez juste besoin d'un dossier" statique "à la racine de votre paquet, et alors vous pouvez utiliser url_for('static', filename='foo.bar') ou lien direct à vos fichiers avec http://example.com/static/foo.bar .

EDIT : comme suggéré dans les commentaires, vous pouvez directement utiliser le '/static/foo.bar' Le chemin D'URL mais url_for() " overhead (performance wise) est assez faible, et l'utiliser signifie que vous serez en mesure de facilement personnaliser le comportement après (changer le dossier, changer le chemin D'URL, déplacer vos fichiers statiques à S3, etc).

66
répondu b4stien 2014-12-27 10:49:59

vous pouvez également, et c'est mon préféré, définir un dossier comme chemin statique de sorte que les fichiers à l'intérieur sont accessibles pour tout le monde.

app = Flask(__name__, static_url_path='/static')

avec cet ensemble, vous pouvez utiliser le HTML standard:

<link rel="stylesheet" type="text/css" href="/static/style.css">
57
répondu sharpshadow 2014-10-24 19:02:06

ce que j'utilise (et cela fonctionne très bien) est un répertoire" templates "et un répertoire" statique". Je place tout mon .les fichiers html/Flacon de modèles à l'intérieur du répertoire de modèles et statique contient CSS/JS. render_template fonctionne très bien pour les fichiers html génériques à ma connaissance, indépendamment de la mesure dans laquelle vous avez utilisé la syntaxe de templating de Flask. Ci-dessous est un exemple d'appel dans mon views.py fichier.

@app.route('/projects')
def projects():
    return render_template("projects.html", title = 'Projects')

assurez-vous d'utiliser url_for() lorsque vous voulez faire référence certains fichiers statiques dans le répertoire statique. Vous finirez probablement par le faire de toute façon dans les liens de vos fichiers CSS/JS en html. Par exemple...

<script src="{{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>

voici un lien vers le tutoriel" canonique " flasque informelle - beaucoup de bons conseils ici pour vous aider à atteindre le point de départ.

http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

31
répondu Kyle Sum 2013-12-18 00:52:38

vous pouvez utiliser cette fonction:

send_static_file(filename)

Fonction utilisée en interne pour envoyer statique fichiers du dossier statique vers le navigateur.

app = Flask(__name__)
@app.route('/<path:path>')
def static_file(path):
    return app.send_static_file(path)
31
répondu BlackMamba 2017-11-08 12:45:55

un exemple de travail le plus simple basé sur les autres réponses est le suivant:

from flask import Flask, request
app = Flask(__name__, static_url_path='')

@app.route('/index/')
def root():
    return app.send_static_file('index.html')

if __name__ == '__main__':
  app.run(debug=True)

avec L'index HTML appelé .html :

<!DOCTYPE html>
<html>
<head>
    <title>Hello World!</title>
</head>
<body>
    <div>
         <p>
            This is a test.
         </p>
    </div>
</body>
</html>

IMPORTANT: et index.html est dans un dossier appelé statique , ce qui signifie <projectpath> a le fichier .py , et <projectpath>\static a le fichier html .

Si vous voulez que le serveur soit visible sur le réseau, utilisez app.run(debug=True, host='0.0.0.0')

EDIT: pour afficher tous les fichiers dans le dossier si demandé, utilisez ce

@app.route('/<path:path>')
def static_file(path):
    return app.send_static_file(path)

qui est essentiellement la réponse de BlackMamba , donnez-leur donc une note positive.

29
répondu EpicPandaForce 2016-07-14 12:23:27

si vous voulez simplement déplacer l'emplacement de vos fichiers statiques, alors la méthode la plus simple est de déclarer les chemins dans le constructeur. Dans l'exemple ci-dessous, j'ai déplacé mes modèles et des fichiers statiques dans un sous-dossier appelé web .

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path='' supprime tout chemin précédent de l'URL (i.e. la valeur par défaut /static ).
  • static_folder='web/static' va dire flasque servir les fichiers trouvés à web/static .
  • template_folder='web/templates' , de même, cela change la le dossier de modèles.

en utilisant cette méthode, L'URL suivante retournera un fichier CSS:

<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">

et enfin, voici un claquement de la structure du dossier, où flask_server.py est l'instance du flacon:

Nested Static Flask Folders

23
répondu Richard Dunn 2017-07-21 14:02:50

pour flux angulaire+boilerplate qui crée l'arbre de dossiers suivant:

backend/
|
|------ui/
|      |------------------build/          <--'static' folder, constructed by Grunt
|      |--<proj           |----vendors/   <-- angular.js and others here
|      |--     folders>   |----src/       <-- your js
|                         |----index.html <-- your SPA entrypoint 
|------<proj
|------     folders>
|
|------view.py  <-- Flask app here

j'utilise la solution suivante:

...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")

@app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
    return send_from_directory(root, path)


@app.route('/', methods=['GET'])
def redirect_to_index():
    return send_from_directory(root, 'index.html')
...

cela aide à redéfinir le dossier 'statique' à personnalisé.

5
répondu user1671599 2015-02-03 23:05:58

donc j'ai fait marcher les choses (basé sur @user1671599 answer) et j'ai voulu le partager avec vous les gars.

(j'espère que je le fais bien puisque c'est ma première application en Python)

j'ai fait cela -

structure du projet:

enter image description here

server.py:

from server.AppStarter import AppStarter
import os

static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")

app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)

AppStarter.py:

from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo


class AppStarter(Resource):
    def __init__(self):
        self._static_files_root_folder_path = ''  # Default is current folder
        self._app = Flask(__name__)  # , static_folder='client', static_url_path='')
        self._api = Api(self._app)

    def _register_static_server(self, static_files_root_folder_path):
        self._static_files_root_folder_path = static_files_root_folder_path
        self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
        self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])

    def register_routes_to_resources(self, static_files_root_folder_path):

        self._register_static_server(static_files_root_folder_path)
        self._api.add_resource(TodoList, '/todos')
        self._api.add_resource(Todo, '/todos/<todo_id>')

    def _goto_index(self):
        return self._serve_page("index.html")

    def _serve_page(self, file_relative_path_to_root):
        return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)

    def run(self, module_name):
        if module_name == '__main__':
            self._app.run(debug=True)
5
répondu danfromisrael 2018-06-26 19:34:55
from flask import redirect, url_for
...
@app.route('/', methods=['GET'])
def metrics():
    return redirect(url_for('static', filename='jenkins_analytics.html'))

ce serveur contient tous les fichiers (css & js... référencé dans votre fichier html.

2
répondu forzagreen 2015-12-28 22:21:59

par défaut, utilisez un dossier" templates "pour contenir tous vos fichiers de template(n'importe quel fichier en texte clair, mais habituellement .html ou une sorte de langage de template tel que jinja2) et un dossier" statique "pour contenir tous vos fichiers statiques(i.e. .js .css et vos images).

   Dans votre routes , vous pouvez utiliser render_template() pour rendre un fichier de modèle (comme je l'ai dit ci-dessus, par défaut il est placé dans le dossier templates ) comme réponse pour votre demande. Et dans le fichier de modèle (c'est généralement une .html fichier), u peut utiliser certains .js et/ou".les fichiers de css, donc je suppose que votre question Est comment u lier ces fichiers statiques au fichier de modèle actuel.

0
répondu Harvey 2013-12-18 13:49:13

Si vous essayez juste d'ouvrir un fichier, vous pouvez utiliser app.open_resource() . Donc lire un fichier ressemblerait à quelque chose comme

with app.open_resource('/static/path/yourfile'):
      #code to read the file and do something
0
répondu Chaitanya Shivade 2017-08-31 02:26:59

la Pensée de partage.... cet exemple.

from flask import Flask
app = Flask(__name__)

@app.route('/loading/')
def hello_world():
    data = open('sample.html').read()    
    return data

if __name__ == '__main__':
    app.run(host='0.0.0.0')

cela fonctionne mieux et simple.

0
répondu Jeevan Chaitanya 2018-10-03 14:01:09