python - images - flask static files
Cómo servir archivos estáticos en matraz (13)
Así que esto es embarazoso. Tengo una aplicación que presenté en Flask
y por ahora solo sirve una página HTML estática con algunos enlaces a CSS y JS. Y no puedo encontrar dónde en la documentación que Flask
describe devolver archivos estáticos. Sí, podría usar render_template
pero sé que los datos no están templados. send_file
pensado que send_file
o url_for
era lo correcto, pero no podía hacer que funcionaran. Mientras tanto, abro los archivos, leo el contenido y preparo una Response
con el tipo de mímeto apropiado:
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)
Alguien quiere dar una muestra de código o url para esto? Sé que esto va a ser muy simple.
Así que tengo las cosas funcionando (basadas en la respuesta de @ user1671599) y quería compartirlas con ustedes.
(Espero hacerlo bien ya que es mi primera aplicación en Python)
Hice esto -
Estructura del proyecto:
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)
De forma predeterminada, el matraz usa una carpeta de "plantillas" para contener todos sus archivos de plantilla (cualquier archivo de texto sin formato, pero generalmente .html
o algún tipo de lenguaje de plantilla como jinja2) y una carpeta "estática" para contener todos sus archivos estáticos ( Es decir .js
.css
y sus imágenes).
En sus routes
, puede usar render_template()
para renderizar un archivo de plantilla (como he dicho anteriormente, por defecto se coloca en la carpeta de templates
) como la respuesta para su solicitud. Y en el archivo de plantilla (generalmente es un archivo tipo .html), u puede usar algunos archivos .js
y / o .css, así que supongo que su pregunta es cómo vincular estos archivos estáticos al archivo de plantilla actual.
El método preferido es usar nginx u otro servidor web para servir archivos estáticos; Podrán hacerlo más eficientemente que Flask.
Sin embargo, puede usar send_from_directory
para enviar archivos desde un directorio, lo que puede ser bastante conveniente en algunas situaciones:
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()
No utilice send_file
o send_static_file
con una ruta proporcionada por el usuario.
Ejemplo de send_static_file
:
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'')
Estoy seguro de que encontrará lo que necesita allí: http://flask.pocoo.org/docs/quickstart/#static-files
Básicamente solo necesita una carpeta "estática" en la raíz de su paquete, y luego puede usar url_for(''static'', filename=''foo.bar'')
o directamente a sus archivos con http://example.com/static/foo.bar .
EDITAR : Como se sugiere en los comentarios, usted podría usar directamente la ruta URL ''/static/foo.bar''
PERO url_for()
sobrecarga (en lo que url_for()
rendimiento) es bastante baja, y su uso significa que podrá personalizar fácilmente el comportamiento después (cambie la carpeta, cambie la ruta de la URL, mueva sus archivos estáticos a S3, etc.).
Lo que uso (y ha funcionado muy bien) es un directorio de "plantillas" y un directorio "estático". Coloco todos mis archivos .html / plantillas de Flask dentro del directorio de plantillas, y static contiene CSS / JS. Según mi conocimiento, render_template funciona bien para archivos html genéricos, independientemente de la medida en que haya utilizado la sintaxis de plantilla de Flask. A continuación hay una llamada de muestra en mi archivo views.py.
@app.route(''/projects'')
def projects():
return render_template("projects.html", title = ''Projects'')
Solo asegúrese de usar url_for () cuando quiera hacer referencia a algún archivo estático en el directorio estático separado. Probablemente termines haciendo esto de todos modos en tus enlaces de archivos CSS / JS en html. Por ejemplo...
<script src="{{ url_for(''static'', filename=''styles/dist/js/bootstrap.js'') }}"></script>
Aquí hay un enlace al tutorial informal "canónico" de Flask: aquí encontrará muchos consejos excelentes para ayudarlo a comenzar.
http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Para el flujo angular + repetitivo que crea el siguiente árbol de carpetas:
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
Uso la siguiente solución:
...
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'')
...
Ayuda a redefinir la carpeta ''estática'' para personalizarla.
Pensamiento de compartir .... este ejemplo.
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'')
Esto funciona mejor y simple.
Puede utilizar esta función:
send_static_file(filename)
Función utilizada internamente para enviar archivos estáticos desde la carpeta estática al navegador.
app = Flask(__name__)
@app.route(''/<path:path>'')
def static_file(path):
return app.send_static_file(path)
Si solo está intentando abrir un archivo, puede usar app.open_resource()
. Así que leer un archivo sería algo así como
with app.open_resource(''/static/path/yourfile''):
#code to read the file and do something
Si solo quiere mover la ubicación de sus archivos estáticos, entonces el método más simple es declarar las rutas en el constructor. En el siguiente ejemplo, moví mis plantillas y archivos estáticos a una subcarpeta llamada web
.
app = Flask(__name__,
static_url_path='''',
static_folder=''web/static'',
template_folder=''web/templates'')
-
static_url_path=''''
elimina cualquier ruta anterior de la URL (es decir, la predeterminada/static
). -
static_folder=''web/static''
le indicará a Flask que sirva los archivos que se encuentran enweb/static
. -
template_folder=''web/templates''
, de manera similar, esto cambia la carpeta de plantillas.
Usando este método, la siguiente URL devolverá un archivo CSS:
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
Y finalmente, aquí hay un complemento de la estructura de carpetas, donde flask_server.py
es la instancia de Flask:
También puede, y este es mi favorito, establecer una carpeta como ruta estática para que los archivos del interior sean accesibles para todos.
app = Flask(__name__, static_url_path=''/static'')
Con ese conjunto puedes usar el HTML estándar:
<link rel="stylesheet" type="text/css" href="/static/style.css">
Un ejemplo de trabajo más simple basado en las otras respuestas es el siguiente:
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)
Con el HTML llamado index.html :
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<div>
<p>
This is a test.
</p>
</div>
</body>
</html>
IMPORTANTE: Y index.html está en una carpeta llamada static , lo que significa que <projectpath>
tiene el archivo .py
, y <projectpath>/static
tiene el archivo html
.
Si desea que el servidor esté visible en la red, use app.run(debug=True, host=''0.0.0.0'')
EDITAR: para mostrar todos los archivos en la carpeta si así lo solicita, use este
@app.route(''/<path:path>'')
def static_file(path):
return app.send_static_file(path)
BlackMamba
es esencialmente la respuesta de BlackMamba
, así que dales un voto positivo.
from flask import redirect, url_for
...
@app.route(''/'', methods=[''GET''])
def metrics():
return redirect(url_for(''static'', filename=''jenkins_analytics.html''))
Esto sirve todos los archivos (css y js ...) a los que se hace referencia en su archivo html.