Obtenga una lista de todas las rutas definidas en la aplicación Flask

145

Tengo una aplicación web compleja basada en Flask. Hay muchos archivos separados con funciones de visualización. Sus URL se definen con el @app.route('/...')decorador. ¿Hay alguna forma de obtener una lista de todas las rutas que se han declarado en mi aplicación? ¿Quizás hay algún método que pueda invocar en el appobjeto?

J-bob
fuente

Respuestas:

152

Todas las rutas para una aplicación se almacenan en lo app.url_mapque es una instancia de werkzeug.routing.Map. Puede iterar sobre las Ruleinstancias utilizando el iter_rulesmétodo:

from flask import Flask, url_for

app = Flask(__name__)

def has_no_empty_params(rule):
    defaults = rule.defaults if rule.defaults is not None else ()
    arguments = rule.arguments if rule.arguments is not None else ()
    return len(defaults) >= len(arguments)


@app.route("/site-map")
def site_map():
    links = []
    for rule in app.url_map.iter_rules():
        # Filter out rules we can't navigate to in a browser
        # and rules that require parameters
        if "GET" in rule.methods and has_no_empty_params(rule):
            url = url_for(rule.endpoint, **(rule.defaults or {}))
            links.append((url, rule.endpoint))
    # links is now a list of url, endpoint tuples

Consulte Mostrar enlaces a nuevas páginas web creadas para obtener un poco más de información.

Sean Vieira
fuente
¡Dulce! Excepto que tuve un problema con la línea url = url_for(rule.endpoint). Acabo de recibir este error BuildError: ('DeleteEvent', {}, None). En cambio, para obtener la url que acabo de hacer url = rule.rule. ¿Alguna idea de por qué tu método no funciona para mí?
J-bob
@ J-bob - lo más probable es que la ruta asociada DeleteEventtenga un parámetro requerido - puede usar ese caso especial o filtrar cualquier regla dondelen(rule.arguments) > len(rule.defaults)
Sean Vieira
Oh, creo que lo entiendo. url_forno se puede generar la URL para ese método sin un parámetro, ¿verdad? OK, pero parece que mi método funciona de todos modos, solo mantiene esa porción si la URL es un parámetro. ¡Gracias!
J-bob
1
Esto es un gran comienzo. ¿Alguna sugerencia sobre cómo crear un servicio web basado en un matraz totalmente autodocumentado, donde se enumeren todos los parámetros (como? Spam = "eggs")? Quizás esta información se pueda extraer de una cadena de documentos de un método de implementación.
Leonid
2
En lugar de usar, el url_for(rule.endpoint)uso rule.rulees mucho mejor porque resuelve casos en los que tiene más de una ruta para el mismo método.
Zini
82

Acabo de encontrar la misma pregunta. Las soluciones anteriores son demasiado complejas. Simplemente abra un nuevo shell debajo de su proyecto:

    python
    >>> from app import app
    >>> app.url_map

La primera ' aplicación ' es mi script de proyecto: app.py , otra es el nombre de mi web.

(esta solución es para web pequeña con una pequeña ruta)

Vi.Ci
fuente
1
Esto probablemente no responde la pregunta directamente. Pero seguro que merece muchos más votos a favor.
UltraInstinct
Esta respuesta es excelente para no requerir que agregue ningún código a su aplicación. Lo usé para obtener la respuesta que quería en segundos sin reconstruir mi código.
joshdick
"¿Hay alguna forma de obtener una lista de todas las rutas que se han declarado en mi aplicación?" Creo que esto responde la pregunta directamente y debería ser la respuesta aceptada. Tan fácil. Gracias.
andho
2
Realmente no veo cómo esto es más simple o más claro que la respuesta aceptada. Sugiere el mismo enfoque, pero lleva más tiempo llegar al punto y no muestra cómo iterar sobre la Mapinstancia o acceder a ninguna de las propiedades de los mensajes de correo electrónico Ruleque contiene, sin los cuales no puede hacer nada útil.
Mark Amery
57

Hago un método auxiliar en mi manage.py:

@manager.command
def list_routes():
    import urllib
    output = []
    for rule in app.url_map.iter_rules():

        options = {}
        for arg in rule.arguments:
            options[arg] = "[{0}]".format(arg)

        methods = ','.join(rule.methods)
        url = url_for(rule.endpoint, **options)
        line = urllib.unquote("{:50s} {:20s} {}".format(rule.endpoint, methods, url))
        output.append(line)

    for line in sorted(output):
        print line

Resuelve el argumento que falta al construir un conjunto ficticio de opciones. El resultado se ve así:

CampaignView:edit              HEAD,OPTIONS,GET     /account/[account_id]/campaigns/[campaign_id]/edit
CampaignView:get               HEAD,OPTIONS,GET     /account/[account_id]/campaign/[campaign_id]
CampaignView:new               HEAD,OPTIONS,GET     /account/[account_id]/new

Luego para ejecutarlo:

python manage.py list_routes

Para más información sobre la gestión de manage.py: http://flask-script.readthedocs.org/en/latest/

Jonathan
fuente
55
Lo anterior funciona muy bien. Sólo cambia urllib.unquotea urllib.parse.unquotey print linea print(line)y funciona en 3.x pitón también.
enjugador
1
Esto no funciona para argumentos que no sean de cadena, en su lugar recomiendo usar la respuesta de John Jiang.
nico
42

Similar a la respuesta de Jonathan, opté por hacer esto en su lugar. No veo el punto de usar url_for ya que se romperá si sus argumentos no son una cadena, por ejemplo, flotante

@manager.command
def list_routes():
    import urllib

    output = []
    for rule in app.url_map.iter_rules():
        methods = ','.join(rule.methods)
        line = urllib.unquote("{:50s} {:20s} {}".format(rule.endpoint, methods, rule))
        output.append(line)

    for line in sorted(output):
        print(line)
John Jiang
fuente
31

Aparentemente, desde la versión 0.11, Flask tiene una CLI incorporada . Uno de los comandos integrados enumera las rutas:

FLASK_APP='my_project.app' flask routes
theY4Kman
fuente
¡Esto es absolutamente brillante!
pfabri
1
flask urlspara mí (0.12.1) Lo vi flask --helppero no veo rutas o URL en la página de CLI
mrgnw
las rutas parecen eliminarse en el matraz 1.1.2
Jerry Ji
5

Como no especificó que debe ejecutarse en la línea de comandos, lo siguiente podría devolverse fácilmente en json para un tablero u otra interfaz que no sea de línea de comandos. El resultado y el resultado realmente no deberían mezclarse desde una perspectiva de diseño de todos modos. Es un mal diseño del programa, incluso si es un programa pequeño. El resultado a continuación podría usarse en una aplicación web, línea de comandos o cualquier otra cosa que ingiera json.

Tampoco especificó que necesitaba conocer la función de Python asociada con cada ruta, por lo que esto responde con mayor precisión a su pregunta original.

Yo uso a continuación para agregar la salida a un panel de monitoreo yo mismo. Si desea los métodos de ruta disponibles (GET, POST, PUT, etc.), deberá combinarlo con otras respuestas anteriores.

La regla repr () se encarga de convertir los argumentos necesarios en la ruta.

def list_routes():
    routes = []

    for rule in app.url_map.iter_rules():
        routes.append('%s' % rule)

    return routes

Lo mismo usando una lista de comprensión:

def list_routes():
    return ['%s' % rule for rule in app.url_map.iter_rules()]

Salida de muestra:

{
  "routes": [
    "/endpoint1", 
    "/nested/service/endpoint2", 
    "/favicon.ico", 
    "/static/<path:filename>"
  ]
}
postal
fuente
2

Si necesita acceder a las funciones de vista, entonces, en lugar de app.url_mapusarlas app.view_functions.

Script de ejemplo:

from flask import Flask

app = Flask(__name__)

@app.route('/foo/bar')
def route1():
    pass

@app.route('/qux/baz')
def route2():
    pass

for name, func in app.view_functions.items():
    print(name)
    print(func)
    print()

Salida de ejecutar el script anterior:

static
<bound method _PackageBoundObject.send_static_file of <Flask '__main__'>>

route1
<function route1 at 0x128f1b9d8>

route2
<function route2 at 0x128f1ba60>

(Tenga en cuenta la inclusión de la ruta "estática", que Flask crea automáticamente).

Mark Amery
fuente
2

Puede ver todas las rutas a través del matraz ejecutando los siguientes comandos después de exportar o configurar la variable de entorno FLASK_APP. flask shell app.url_map

Xerrex
fuente
1

dentro de su aplicación de matraz:

flask shell
>>> app.url_map
Map([<Rule '/' (OPTIONS, HEAD, GET) -> helloworld>,
 <Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>])
Nabaz Maaruf
fuente