Archivos estáticos en Flask: robot.txt, sitemap.xml (mod_wsgi)

94

¿Existe alguna solución inteligente para almacenar archivos estáticos en el directorio raíz de la aplicación de Flask? Se espera que robots.txt y sitemap.xml se encuentren en /, por lo que mi idea fue crear rutas para ellos:

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

Debe haber algo más conveniente :)

biesiad
fuente

Respuestas:

78

La mejor manera es establecer static_url_path en la URL raíz

from flask import Flask

app = Flask(__name__, static_folder='static', static_url_path='')
dns
fuente
Vale la pena mencionar que static_folder no tiene que estar en la carpeta del proyecto. por ejemplo, static_folder = '/ app / ui' está bien.
ashic
66

@vonPetrushev tiene razón, en producción querrá entregar archivos estáticos a través de nginx o apache, pero para el desarrollo es bueno que su entorno de desarrollo sea simple, ya que su aplicación Python también ofrece contenido estático para que no tenga que preocuparse sobre el cambio de configuraciones y múltiples proyectos. Para hacer eso, querrá usar 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')
    })

Este ejemplo asume que sus archivos estáticos están en la carpeta "static", ajústelos a lo que se ajuste a su entorno.

Philip Southam
fuente
1
¡GRACIAS! ¡Esto es lo que necesitaba! Estoy buscando hacer esto para mi heroku de producción. Vea las respuestas en el siguiente hilo: flask.pocoo.org/mailinglist/archive/2012/2/22/…
David
2
Atención: ahora hay una manera más fácil de manejar esto. Revisa mi respuesta.
Sean McSomething
1
Sin embargo, ¿hay alguna manera de que SharedDataMiddleware resuelva solo '/' en index.html o similar?
Gromgull
63

La respuesta más limpia a esta pregunta es la respuesta a esta pregunta (idéntica) :

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:])

Para resumir:

  • como señaló David, con la configuración correcta está bien servir algunos archivos estáticos a través de prod
  • buscar /robots.txt no debería resultar en una redirección a /static/robots.txt. (En la respuesta de Seans, no está claro de inmediato cómo se logra).
  • no es limpio agregar archivos estáticos a la carpeta raíz de la aplicación
  • finalmente, la solución propuesta parece mucho más limpia que el enfoque de agregar middleware:
bebbi
fuente
23

A pesar de que esta es una vieja pregunta respondida, estoy respondiendo esto porque esta publicación aparece bastante arriba en los resultados de Google. Si bien no está cubierto en la documentación, si lee los documentos de la API para el constructor de objetos Flask Application, está cubierto. Pasando el parámetro nombrado static_folderasí:

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

... puede definir desde dónde se sirven los archivos estáticos. Del mismo modo, puede definir a template_folder, su nombre static_url_path.

Sean McSomething
fuente
@chmike sí, está predeterminado, /staticpero puede cambiarlo anulando static_url_path.
Sean McSomething
Esto es correcto, pero otras respuestas son más flexibles. Este está limitado por el hecho de que solo puede servir una ruta de directorio.
Thomas Dignan
Esta no es la respuesta a la pregunta original.
Paolo Casciello
2
Si establece static_url_path en "", puede servir archivos desde /.
Beau
Esto obliga a Flask a servir archivos estáticos. ¿Qué pasa si quieres que nginx o apache les sirva?
Markon
15

El servicio de archivos estáticos no tiene nada que ver con la aplicación que está destinada a entregar contenido dinámico. La forma correcta de servir archivos estáticos depende del servidor que esté utilizando. Después de todo, cuando tenga su aplicación en funcionamiento, deberá vincularla a un servidor web. Solo puedo hablar por apache httpd, por lo que la forma de servir archivos estáticos se define en el host virtual que está vinculando a su aplicación a través de mod-wsgi. Aquí está la guía que le mostrará cómo servir mapas del sitio, robots.txt o cualquier contenido estático: http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_At_Root_Of_Site

vonPetrushev
fuente
Esa es la respuesta que he estado buscando. ¡Gracias!
biesiad
1
Una aplicación está destinada a entregar contenido, algo dinámico y algo estático.
Dem Pilafian
14

Otra forma de enviar archivos estáticos es usar una regla general como esta:

@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()

Utilizo esto para tratar de minimizar la configuración durante el desarrollo. Obtuve la idea de http://flask.pocoo.org/snippets/57/

Además, estoy desarrollando usando flask en mi máquina independiente pero implementando con Apache en el servidor de producción. Yo suelo:

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
fuente
1
Atención: ahora hay una manera más fácil de manejar esto. Revisa mi respuesta.
Sean McSomething
¡Excelente manera si necesita servir múltiples caminos!
Thomas Dignan
6

Esto podría haberse agregado desde que se hizo esta pregunta, pero estaba mirando a través de "helpers.py" de flask y encontré 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.
'''

... que hace referencia a flask.send_file:

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

... que parece mejor para un mayor control, aunque send_from_directory pasa ** opciones directamente a send_file.

blast_hardcheese
fuente
3

De la documentación aquí: http://flask.pocoo.org/docs/quickstart/#static-files

Las aplicaciones web dinámicas también necesitan archivos estáticos. Por lo general, de ahí provienen los archivos CSS y JavaScript. Idealmente, su servidor web está configurado para servirlos por usted, pero durante el desarrollo, Flask también puede hacerlo. Simplemente cree una carpeta llamada static en su paquete o junto a su módulo y estará disponible en / static en la aplicación.

Para generar URL a esa parte de la URL, use el nombre de URL 'estático' especial:

url_for ('estático', nombre de archivo = 'estilo.css')

El archivo debe almacenarse en el sistema de archivos como static / style.css.

Josh Klein
fuente
0

Yo también tengo el mismo dilema. Hice una búsqueda y encontré mi respuesta (MHO):

También podría citar de la documentación.

Las aplicaciones web dinámicas también necesitan archivos estáticos. Por lo general, es de ahí de donde provienen los archivos CSS y JavaScript. Idealmente, su servidor web está configurado para servirlos por usted, pero durante el desarrollo, Flask también puede hacerlo . Simplemente cree una carpeta llamada static en su paquete o junto a su módulo y estará disponible en / static en la aplicación.

En mi humilde opinión: cuando su aplicación está en producción , el servicio de archivos estáticos debe estar (o idealmente) configurado en el servidor web (nginx, apache); pero durante el desarrollo , Flask lo puso a disposición para servir archivos estáticos. Esto es para ayudarle a desarrollarse rápidamente, sin necesidad de configurar servidores web ni nada por el estilo.

Espero eso ayude.

jpanganiban
fuente
0

Prueba esto:

@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
fuente