Fichiers statiques dans Flask - robot.txt, sitemap.xml (mod_wsgi)

94

Existe-t-il une solution intelligente pour stocker des fichiers statiques dans le répertoire racine de l'application Flask. On s'attend à ce que les robots.txt et sitemap.xml se trouvent dans /, donc mon idée était de créer des routes pour eux:

@app.route('/sitemap.xml', methods=['GET'])
def sitemap():
  response = make_response(open('sitemap.xml').read())
  response.headers["Content-type"] = "text/plain"
  return response

Il doit y avoir quelque chose de plus pratique :)

Biesiad
la source

Réponses:

78

Le meilleur moyen est de définir static_url_path sur l'url racine

from flask import Flask

app = Flask(__name__, static_folder='static', static_url_path='')
DNS
la source
Il est à noter que le static_folder n'a pas besoin d'être dans le dossier du projet. par exemple, static_folder = '/ app / ui' est bien.
ashic
66

@vonPetrushev a raison, en production, vous voudrez servir des fichiers statiques via nginx ou apache, mais pour le développement, c'est bien d'avoir votre environnement de développement simple avec votre application python servant également le contenu statique afin que vous n'ayez pas à vous inquiéter sur la modification des configurations et plusieurs projets. Pour ce faire, vous voudrez utiliser le SharedDataMiddleware .

from flask import Flask
app = Flask(__name__)
'''
Your app setup and code
'''
if app.config['DEBUG']:
    from werkzeug import SharedDataMiddleware
    import os
    app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
      '/': os.path.join(os.path.dirname(__file__), 'static')
    })

Cet exemple suppose que vos fichiers statiques sont dans le dossier «static», ajustez-les à ce qui convient à votre environnement.

Philip Southam
la source
1
MERCI! C'est ce dont j'avais besoin! Je cherche à faire ça pour mon heroku de production. Voir les réponses sur le fil suivant: flask.pocoo.org/mailinglist/archive/2012/2/22/…
David
2
Attention, il existe un moyen plus simple de gérer cela maintenant. Vérifiez ma réponse.
Sean McSomething le
1
Existe-t-il un moyen pour SharedDataMiddleware de résoudre simplement «/» en index.html ou similaire?
gromgull
63

La propre réponse à cette question est la réponse à cette (identique) question :

from flask import Flask, request, send_from_directory
app = Flask(__name__, static_folder='static')    

@app.route('/robots.txt')
@app.route('/sitemap.xml')
def static_from_root():
    return send_from_directory(app.static_folder, request.path[1:])

Résumer:

  • comme David l'a souligné, avec la bonne configuration, il est possible de servir quelques fichiers statiques via prod
  • la recherche de /robots.txt ne devrait pas entraîner une redirection vers /static/robots.txt. (Dans la réponse de Seans, il n'est pas immédiatement clair comment cela est réalisé.)
  • ce n'est pas propre d'ajouter des fichiers statiques dans le dossier racine de l'application
  • enfin, la solution proposée semble beaucoup plus propre que l’approche d’ajout de middleware:
bebbi
la source
23

Même s'il s'agit d'une vieille question avec réponse, je réponds à cela car cet article occupe une place assez importante dans les résultats de Google. Bien que cela ne soit pas couvert dans la documentation, si vous lisez la documentation de l' API pour le constructeur d'objet Flask Application, cela est couvert. En passant le paramètre nommé static_foldercomme ceci:

from flask import Flask
app = Flask(__name__,
            static_folder="/path/to/static",
            template_folder="/path/to/templates")

... vous pouvez définir la provenance des fichiers statiques. De même, vous pouvez définir un template_folder, le nom de vous static_url_path.

Sean McSomething
la source
@chmike oui, par défaut, /staticmais vous pouvez changer cela en remplaçant static_url_path.
Sean McSomething
C'est correct mais les autres réponses sont plus flexibles. Celui-ci est limité par le fait qu'il ne peut servir qu'un seul chemin de répertoire.
Thomas Dignan
Ce n'est pas la réponse à la question initiale.
Paolo Casciello
2
Si vous définissez static_url_path sur "", vous pouvez servir des fichiers à partir de /.
Beau
Cela force Flask à servir des fichiers statiques. Et si vous voulez que Nginx ou Apache les serve?
Markon
15

La diffusion de fichiers statiques n'a rien à voir avec une application destinée à fournir un contenu dynamique. La manière correcte de servir les fichiers statiques dépend du serveur que vous utilisez. Après tout, lorsque votre application sera opérationnelle, vous devrez la lier à un serveur Web. Je ne peux parler que pour apache httpd, donc la manière de servir les fichiers statiques est définie dans l'hôte virtuel que vous liez à votre application via mod-wsgi. Voici le guide qui vous montrera comment diffuser des sitemaps, des robots.txt ou tout autre contenu statique: http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_At_Root_Of_Site

vonPetrushev
la source
C'est la réponse que je cherchais. Merci!
biesiad
1
Une application est destinée à fournir du contenu, certains dynamiques et d'autres statiques.
Dem Pilafian
14

Une autre façon d'envoyer des fichiers statiques consiste à utiliser une règle fourre-tout comme celle-ci:

@app.route('/<path:path>')
def catch_all(path):
    if not app.debug:
        flask.abort(404)
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    return f.read()

J'utilise ceci pour essayer de minimiser la configuration lors du développement. J'ai eu l'idée de http://flask.pocoo.org/snippets/57/

De plus, je développe en utilisant flask sur ma machine autonome mais en déployant avec Apache dans un serveur de production. J'utilise:

file_suffix_to_mimetype = {
    '.css': 'text/css',
    '.jpg': 'image/jpeg',
    '.html': 'text/html',
    '.ico': 'image/x-icon',
    '.png': 'image/png',
    '.js': 'application/javascript'
}
def static_file(path):
    try:
        f = open(path)
    except IOError, e:
        flask.abort(404)
        return
    root, ext = os.path.splitext(path)
    if ext in file_suffix_to_mimetype:
        return flask.Response(f.read(), mimetype=file_suffix_to_mimetype[ext])
    return f.read()

[...]

if __name__ == '__main__':
    parser = optparse.OptionParser()
    parser.add_option('-d', '--debug', dest='debug', default=False,
                      help='turn on Flask debugging', action='store_true')

    options, args = parser.parse_args()

    if options.debug:
        app.debug = True
        # set up flask to serve static content
        app.add_url_rule('/<path:path>', 'static_file', static_file)
    app.run()
Ben Golding
la source
1
Attention, il existe un moyen plus simple de gérer cela maintenant. Vérifiez ma réponse.
Sean McSomething le
Excellent moyen si vous devez desservir plusieurs chemins!
Thomas Dignan
6

Cela a peut-être été ajouté depuis que cette question a été posée, mais je regardais dans le "helpers.py" de flask et j'ai trouvé flask.send_from_directory:

send_from_directory(directory, filename, **options)
'''
  send_from_directory(directory, filename, **options)
  Send a file from a given directory with send_file.  This
  is a secure way to quickly expose static files from an upload folder
  or something similar.
'''

... qui fait référence à flask.send_file:

send_file(filename_or_fp, mimetype=None, as_attachment=False, attachment_filename=None, add_etags=True, cache_timeout=43200, conditional=False)

... ce qui semble mieux pour plus de contrôle, bien que send_from_directory transmette ** les options directement à send_file.

blast_hardcheese
la source
3

De la documentation ici: http://flask.pocoo.org/docs/quickstart/#static-files

Les applications Web dynamiques ont également besoin de fichiers statiques. C'est généralement de là que proviennent les fichiers CSS et JavaScript. Idéalement, votre serveur Web est configuré pour les servir pour vous, mais pendant le développement, Flask peut le faire également. Créez simplement un dossier appelé static dans votre package ou à côté de votre module et il sera disponible sur / static sur l'application.

Pour générer des URL vers cette partie de l'URL, utilisez le nom d'URL «statique» spécial:

url_for ('statique', nom de fichier = 'style.css')

Le fichier doit être stocké sur le système de fichiers en tant que static / style.css.

Josh Klein
la source
0

J'ai aussi le même dilemme. J'ai fait une recherche et j'ai trouvé ma réponse (MHO):

Autant citer la documentation

Les applications Web dynamiques ont également besoin de fichiers statiques. C'est généralement de là que proviennent les fichiers CSS et JavaScript. Idéalement, votre serveur Web est configuré pour les servir pour vous, mais pendant le développement, Flask peut le faire également . Créez simplement un dossier appelé static dans votre package ou à côté de votre module et il sera disponible sur / static sur l'application.

IMHO: Lorsque votre application est en production , le service de fichiers statiques doit être (ou est idéalement) configuré sur le serveur Web (nginx, apache); mais pendant le développement , Flask l'a rendu disponible pour servir des fichiers statiques. Ceci vous permet de vous développer rapidement - pas besoin de configurer des serveurs Web et autres.

J'espère que ça aide.

jpanganiban
la source
0

Essaye ça:

@app.route("/ProtectedFolder/<path:filename>")
@CheckUserSecurityAccessConditions
def Protect_Content(filename):
  return send_from_directory((os.path.join(os.path.dirname(__file__), 'ProtectedFolder')),filename)
Farzad Amirjavid
la source