web-dev-qa-db-fra.com

Comment servir des fichiers statiques dans un flacon

C'est donc embarrassant. J'ai créé une application dans Flask et, pour l'instant, elle 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 des fichiers statiques. Oui, je pourrais utiliser render_template mais je sais que les données ne sont pas modélisées. J'aurais pensé que send_file ou url_for était la bonne chose, mais je ne pouvais pas les faire fonctionner. Entre-temps, j'ouvre les fichiers, lit le contenu et configure une Response avec le type MIME 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 __== '__main__':  # pragma: no cover
    app.run(port=80)

Quelqu'un veut donner un exemple de code ou une URL pour cela? Je sais que ça va être très simple.

355
hughdbrown

La méthode recommandée consiste à utiliser nginx ou un autre serveur Web pour servir des fichiers statiques. ils seront capables de le faire plus efficacement que Flask.

Cependant, vous pouvez utiliser send_from_directory pour envoyer des fichiers depuis un répertoire, ce qui peut s'avérer très 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 __== "__main__":
    app.run()

Utilisez not utilisez send_file ou send_static_file avec un chemin fourni par l'utilisateur.

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')
474
atupal

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

En gros, vous avez simplement besoin d’un dossier "statique" à la racine de votre paquet, puis vous pouvez utiliser url_for('static', filename='foo.bar') ou lier directement vos fichiers avec http://example.com/static/foo.bar .

EDIT: comme suggéré dans les commentaires, vous pouvez directement utiliser le chemin '/static/foo.bar' de l'URL MAISurl_for() est relativement faible (en termes de performances) et son utilisation signifie personnalisez ensuite le comportement (changez le dossier, changez le chemin de l'URL, déplacez vos fichiers statiques vers S3, etc.).

70
b4stien

Vous pouvez également, et c'est mon préféré, définir un dossier en tant que chemin statique pour que les fichiers qu'il contient soient accessibles à tous.

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

Avec cet ensemble, vous pouvez utiliser le code HTML standard:

<link rel="stylesheet" type="text/css" href="/static/style.css">
62
sharpshadow

Si vous souhaitez simplement déplacer l'emplacement de vos fichiers statiques, la méthode la plus simple consiste à déclarer les chemins dans le constructeur. Dans l'exemple ci-dessous, j'ai déplacé mes modèles et 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 (c'est-à-dire . le /static par défaut).
  • static_folder='web/static' dira à Flask de servir les fichiers trouvés à web/static.
  • template_folder='web/templates', de même, cela change le dossier templates.

En utilisant cette méthode, l'URL suivante renverra un fichier CSS:

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

Et enfin, voici un aperçu de la structure du dossier, où flask_server.py est l'instance Flask:

 Nested Static Flask Folders

38
Richard Dunn

Ce que j'utilise (et cela fonctionne très bien) est un répertoire "templates" et un répertoire "statique". Je place tous mes fichiers .html/modèles Flask dans le répertoire templates, et static contient CSS/JS. A ma connaissance, render_template fonctionne très bien pour les fichiers HTML génériques, quelle que soit la mesure dans laquelle vous avez utilisé la syntaxe de template de Flask. Vous trouverez ci-dessous un exemple d'appel dans mon fichier views.py.

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

Assurez-vous simplement d’utiliser url_for () lorsque vous souhaitez référencer un fichier statique dans le répertoire statique séparé. Vous finirez probablement par le faire de toute façon dans vos liens de fichiers CSS/JS au format HTML. Par exemple...

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

Voici un lien vers le didacticiel informel "canonique" de Flask - de nombreux conseils utiles pour vous aider à démarrer. 

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

33
Kyle Sum

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 __== '__main__':
  app.run(debug=True)

Avec le code HTML appelé index.html:

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

IMPORTANT: And index.html se trouve dans un dossier appelé static , ce qui signifie que <projectpath> contient le fichier .py et <projectpath>\static le fichier html.

Si vous souhaitez 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 du dossier si nécessaire, utilisez cette commande.

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

Ce qui est essentiellement la réponse de BlackMamba, donnez-leur un vote positif.

31
EpicPandaForce

Pour un flux angulaire + passe-partout créant une arborescence de dossiers suivante:

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')
...

Il est utile de redéfinir le dossier 'statique' en un dossier personnalisé.

7
user1671599

Je me suis donc mis au travail (à partir de la réponse @ user1671599) et je voulais le partager avec vous.

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

J'ai fait ça -

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
danfromisrael

Pensée de partager .... cet exemple.

from flask import Flask
app = Flask(__name__)

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

if __== '__main__':
    app.run(Host='0.0.0.0')

Cela fonctionne mieux et simple.

3
Jeevan Chaitanya
from flask import redirect, url_for
...
@app.route('/', methods=['GET'])
def metrics():
    return redirect(url_for('static', filename='jenkins_analytics.html'))

Cela sert tous les fichiers (css & js ...) référencés dans votre fichier html.

2
forzagreen

Toutes les réponses sont bonnes mais ce qui a bien fonctionné pour moi est d’utiliser la simple fonction send_file de Flask. Cela fonctionne bien lorsque vous avez juste besoin d'envoyer un fichier HTML en réponse lorsque Host: port/ApiName affichera le résultat de le fichier dans le navigateur


@app.route('/ApiName')
def ApiFunc():
    try:
        return send_file('some-other-directory-than-root/your-file.extension')
    except Exception as e:
        logging.info(e.args[0])```

1
Binoy S Kumar

Si vous essayez simplement 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
Chaitanya Shivade

Un des moyen simple de faire. Salut!

demo.py

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def index():
   return render_template("index.html")

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

Créez maintenant un nom de dossier appelé templates . Ajoutez votre index.html fichier à l'intérieur de templates folder

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Python Web Application</title>
</head>
<body>
    <div>
         <p>
            Welcomes You!!
         </p>
    </div>
</body>
</html>

Structure du projet

-demo.py
-templates/index.html
0
Maheshvirus

Par défaut, flask utilise un dossier "templates" pour contenir tous vos fichiers modèles (tout fichier en texte brut, mais généralement .html ou une sorte de langage de modèle tel que jinja2) et un dossier "statique" pour contenir tous vos fichiers statiques (c'est-à-dire .js.css et vos images). 
Dans votre routes, vous pouvez utiliser render_template() pour restituer un fichier de modèle (comme je le dis ci-dessus, par défaut, il est placé dans le dossier templates) en tant que réponse à votre demande. Et dans le fichier de modèle (il s’agit généralement d’un fichier de type .html), vous pouvez utiliser des fichiers .js et/ou `.css '. Votre question est donc de savoir comment vous liez ces fichiers statiques au fichier de modèle actuel. 

0
Harvey