Añadir un prefijo a todas las rutas del frasco
Tengo un prefijo que quiero añadir a cada ruta. Ahora mismo agrego una constante a la ruta en cada definición. ¿Hay alguna manera de hacer esto automáticamente?
PREFIX = "/abc/123"
@app.route(PREFIX + "/")
def index_page():
return "This is a website about burritos"
@app.route(PREFIX + "/about")
def about_page():
return "This is a website about burritos"
8 answers
La respuesta depende de cómo está sirviendo esta solicitud.
Sub-montado dentro de otro contenedor WSGI
Suponiendo que va a ejecutar esta aplicación dentro de un contenedor WSGI (mod_wsgi, uwsgi, gunicorn, etc); necesita realmente montar, en ese prefijo la aplicación como una sub-parte de ese contenedor WSGI (cualquier cosa que hable WSGI hará) y establecer su APPLICATION_ROOT
valor de configuración para su prefijo:
app.config["APPLICATION_ROOT"] = "/abc/123"
@app.route("/")
def index():
return "The URL for this page is {}".format(url_for("index"))
# Will return "The URL for this page is /abc/123/"
Estableciendo el APPLICATION_ROOT
el valor de configuración simplemente limita la cookie de sesión de Flask a ese prefijo de URL. Todo lo demás se manejará automáticamente por ti mediante las excelentes capacidades de manejo WSGI de Flask y Werkzeug.
Un ejemplo de sub-montar correctamente su aplicación
Si no está seguro de lo que significa el primer párrafo, eche un vistazo a esta aplicación de ejemplo con Matraz montado dentro de ella:
from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/abc/123'
@app.route('/')
def index():
return 'The URL for this page is {}'.format(url_for('index'))
def simple(env, resp):
resp(b'200 OK', [(b'Content-Type', b'text/plain')])
return [b'Hello WSGI World']
app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app})
if __name__ == '__main__':
app.run('localhost', 5000)
Proxy de solicitudes a la aplicación
Si, por otro lado, usted será ejecutar su aplicación Flask en la raíz de su contenedor WSGI y proxy de solicitudes a ella (por ejemplo, si está siendo FASTCGI'd a, o si nginx es proxy_pass
-ing solicitudes para un sub-endpoint a su stand-alone uwsgi
/ gevent
servidor entonces usted puede:
- Usa un Plano, como Miguel señala en su respuesta.
-
o use el
DispatcherMiddleware
dewerkzeug
(o elPrefixMiddleware
de la respuesta de su27) para sub-montar su aplicación en el servidor WSGI independiente estás consumiendo. (Ver Un ejemplo de sub-montar correctamente su aplicación anterior para el código a utilizar).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:51
Puedes poner tus rutas en un plano:
bp = Blueprint('burritos', __name__,
template_folder='templates')
@bp.route("/")
def index_page():
return "This is a website about burritos"
@bp.route("/about")
def about_page():
return "This is a website about burritos"
Luego registra el blueprint con la aplicación usando un prefijo:
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-23 21:24:12
Debe tener en cuenta que el APPLICATION_ROOT
NO es para este propósito.
Todo lo que tienes que hacer es escribir un middleware para hacer los siguientes cambios:
- modifica
PATH_INFO
para manejar la url prefijada. - modifica
SCRIPT_NAME
para generar la url prefijada.
Así:
class PrefixMiddleware(object):
def __init__(self, app, prefix=''):
self.app = app
self.prefix = prefix
def __call__(self, environ, start_response):
if environ['PATH_INFO'].startswith(self.prefix):
environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
environ['SCRIPT_NAME'] = self.prefix
return self.app(environ, start_response)
else:
start_response('404', [('Content-Type', 'text/plain')])
return ["This url does not belong to the app.".encode()]
Envuelve tu app con el middleware, así:
from flask import Flask, url_for
app = Flask(__name__)
app.debug = True
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo')
@app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
if __name__ == '__main__':
app.run('0.0.0.0', 9010)
Visita http://localhost:9010/foo/bar
,
Obtendrá el resultado correcto: The URL for this page is /foo/bar
Y no olvide configurar el dominio de cookies si necesito hacerlo.
Esta solución viene dada por la esencia de Larivact. El APPLICATION_ROOT
no es para este trabajo, aunque parece ser. Es muy confuso.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-14 06:55:33
Esta es más una respuesta python que una respuesta Flask/werkzeug; pero es simple y funciona.
Si, como yo, desea que la configuración de su aplicación (cargada desde un archivo .ini
) también contenga el prefijo de su aplicación Flask (por lo tanto, no debe tener el valor establecido durante la implementación, sino durante el tiempo de ejecución), puede optar por lo siguiente:
def prefix_route(route_function, prefix='', mask='{0}{1}'):
'''
Defines a new route function with a prefix.
The mask argument is a `format string` formatted with, in that order:
prefix, route
'''
def newroute(route, *args, **kwargs):
'''New function to prefix the route'''
return route_function(mask.format(prefix, route), *args, **kwargs)
return newroute
Podría decirse que esto es algo hackish y se basa en el hecho de que la función de ruta del matraz requiere a route
como primera posicional argumento.
Puedes usarlo así:
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
NB: No vale nada que sea posible usar una variable en el prefijo (por ejemplo configurándolo a /<prefix>
), y luego procesar este prefijo en las funciones que decores con tu @app.route(...)
. Si lo hace, obviamente tiene que declarar el parámetro prefix
en su(s) función (es) decorada (s). Además, es posible que desee comprobar el prefijo enviado contra algunas reglas, y devolver un 404 si la comprobación falla. Para evitar un 404 re-implementación personalizada, por favor from werkzeug.exceptions import NotFound
y luego raise NotFound()
si la comprobación falla.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-10 16:28:14
Por lo tanto, creo que una respuesta válida a esto es: el prefijo debe configurarse en la aplicación de servidor real que use cuando se complete el desarrollo. Apache, nginx, etc.
Sin embargo, si desea que esto funcione durante el desarrollo mientras ejecuta la aplicación Flask en debug, eche un vistazo a esta síntesis.
Frasco de DispatcherMiddleware
al rescate!
Voy a copiar el código aquí para la posteridad:
"Serve a Flask app on a sub-url during localhost development."
from flask import Flask
APPLICATION_ROOT = '/spam'
app = Flask(__name__)
app.config.from_object(__name__) # I think this adds APPLICATION_ROOT
# to the config - I'm not exactly sure how!
# alternatively:
# app.config['APPLICATION_ROOT'] = APPLICATION_ROOT
@app.route('/')
def index():
return 'Hello, world!'
if __name__ == '__main__':
# Relevant documents:
# http://werkzeug.pocoo.org/docs/middlewares/
# http://flask.pocoo.org/docs/patterns/appdispatch/
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
app.config['DEBUG'] = True
# Load a dummy app at the root URL to give 404 errors.
# Serve app at APPLICATION_ROOT for localhost development.
application = DispatcherMiddleware(Flask('dummy_app'), {
app.config['APPLICATION_ROOT']: app,
})
run_simple('localhost', 5000, application, use_reloader=True)
Ahora, al ejecutar el código anterior como una aplicación Flask independiente, http://localhost:5000/spam/
mostrará Hello, world!
.
En un comentario sobre otra respuesta, expresé que deseaba hacer algo como esto:
from flask import Flask, Blueprint
# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
app.run()
# I now would like to be able to get to my route via this url:
# http://host:8080/api/some_submodule/record/1/
Aplicando DispatcherMiddleware
a mi ejemplo artificial:
from flask import Flask, Blueprint
from flask.serving import run_simple
from flask.wsgi import DispatcherMiddleware
# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
application = DispatcherMiddleware(Flask('dummy_app'), {
app.config['APPLICATION_ROOT']: app
})
run_simple('localhost', 5000, application, use_reloader=True)
# Now, this url works!
# http://host:8080/api/some_submodule/record/1/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-18 19:52:07
Necesitaba la llamada "raíz de contexto"similar. Lo hice en el fichero conf bajo /etc/httpd / conf.d / usando WSGIScriptAlias:
Myapp.conf:
<VirtualHost *:80>
WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py
<Directory /home/<myid>/myapp>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
Así que ahora puedo acceder a mi aplicación como : http://localhost:5000/myapp
Ver la guía - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-11 18:20:38
Otra forma completamente diferente es con puntos de montaje{[14] {} en[3]}.
Del documento acerca de El alojamiento de varias aplicaciones en el mismo proceso (permalink ).
En su uwsgi.ini
usted agrega
[uwsgi]
mount = /foo=main.py
manage-script-name = true
# also stuff which is not relevant for this, but included for completeness sake:
module = main
callable = app
socket = /tmp/uwsgi.sock
Si no llamas a tu archivo main.py
, necesitas cambiar tanto el mount
como el module
Su main.py
podría verse así: {[15]]}
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
# end def
Y una configuración de nginx (de nuevo para completar):
server {
listen 80;
server_name example.com
location /foo {
include uwsgi_params;
uwsgi_pass unix:///temp/uwsgi.sock;
}
}
Ahora llamando example.com/foo/bar
se mostrará /foo/bar
como devuelto por el matraz url_for('bar')
, ya que se adapta automáticamente. De esa manera tus enlaces funcionarán sin problemas de prefijo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-07 10:13:53
Siempre prefiero usar lo siguiente cuando se trata de agregar un prefijo en todo app
:
app = Flask(__name__, root_path='/operators')
Limpio y claro.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-07 10:39:17