Obtenir la liste de toutes les routes définies dans l'application Flask

145

J'ai une application Web complexe basée sur Flask. Il existe de nombreux fichiers séparés avec des fonctions d'affichage. Leurs URL sont définies avec le @app.route('/...')décorateur. Existe-t-il un moyen d'obtenir une liste de toutes les routes qui ont été déclarées dans mon application? Peut-être y a-t-il une méthode que je peux appeler sur l' appobjet?

J-bob
la source

Réponses:

152

Toutes les routes d'une application sont stockées sur app.url_maplesquelles se trouve une instance de werkzeug.routing.Map. Vous pouvez parcourir les Ruleinstances en utilisant la iter_rulesméthode:

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

Voir Afficher les liens vers de nouvelles pages Web créées pour un peu plus d'informations.

Sean Vieira
la source
Doux! Sauf que j'ai eu un problème avec la ligne url = url_for(rule.endpoint). Je viens de recevoir cette erreur BuildError: ('DeleteEvent', {}, None). Au lieu de cela, pour obtenir l'url que je viens de faire url = rule.rule. Une idée de la raison pour laquelle votre méthode ne fonctionne pas pour moi?
J-bob
@ J-bob - très probablement l'itinéraire associé à DeleteEventa un paramètre obligatoire - vous pouvez soit le cas spécial, soit filtrer toutes les règles oùlen(rule.arguments) > len(rule.defaults)
Sean Vieira
Oh je pense que je comprends. url_forne peut pas générer l'URL pour ce methid sans paramètre, non? OK, mais il semble que ma méthode fonctionne de toute façon, elle conserve simplement cette partie si l'URL est un paramètre. Merci!
J-bob
1
Ceci est un bon début. Avez-vous des suggestions sur la façon de créer un service Web entièrement auto-documenté basé sur des flacons, où tous les paramètres (tels que? Spam = "eggs") sont répertoriés? Peut-être que cette information peut être extraite d'une docstring d'une méthode d'implémentation.
Leonid
2
Au lieu d'utiliser l' url_for(rule.endpoint)utilisation rule.rulequi est beaucoup mieux résoudre beacause cas où vous avez plus d'une voie pour la même méthode.
Zini
84

Je viens de rencontrer la même question. La solution ci-dessus est trop complexe. Ouvrez simplement un nouveau shell sous votre projet:

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

La première « application » est le script de mon projet: app.py , une autre est le nom de mon site Web.

(cette solution est pour un petit Web avec un petit itinéraire)

Vi.Ci
la source
1
Cela ne répond probablement pas directement à la question. Mais cela mérite certainement beaucoup plus de votes positifs.
UltraInstinct
Cette réponse est idéale pour ne pas vous obliger à ajouter de code à votre application. Je l'ai utilisé pour obtenir la réponse que je voulais en quelques secondes sans reconstruire mon code.
joshdick
"Existe-t-il un moyen d'obtenir une liste de toutes les routes qui ont été déclarées dans mon application?" Je pense que cela répond directement à la question et devrait être la réponse acceptée. Si facile. Merci.
andho
2
Je ne vois pas vraiment comment cela est plus simple ou plus clair que la réponse acceptée. Cela suggère la même approche, mais prend plus de temps pour aller au but et ne montre pas comment parcourir l' Mapinstance ou accéder à l'une des propriétés des Rules qu'elle contient, sans lesquelles vous ne pouvez rien faire d'utile.
Mark Amery
57

Je crée une méthode d'aide sur mon 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

Il résout l'argument manquant en créant un ensemble d'options factice. La sortie ressemble à:

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

Ensuite, pour l'exécuter:

python manage.py list_routes

Pour en savoir plus sur manage.py checkout: http://flask-script.readthedocs.org/en/latest/

Jonathan
la source
5
Ce qui précède fonctionne très bien. Changez simplement urllib.unquotevers urllib.parse.unquoteet print linevers print(line)et cela fonctionne également en python 3.x.
raclette
1
Cela ne fonctionne pas pour les arguments sans chaîne, je recommande d'utiliser la réponse de John Jiang à la place.
nico
42

Semblable à la réponse de Jonathan, j'ai choisi de le faire à la place. Je ne vois pas l'intérêt d'utiliser url_for car il se cassera si vos arguments ne sont pas des chaînes, par exemple float

@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
la source
32

Apparemment, depuis la version 0.11, Flask a une CLI intégrée . L'une des commandes intégrées répertorie les routes:

FLASK_APP='my_project.app' flask routes
theY4Kman
la source
C'est absolument génial!
pfabri
1
flask urlspour moi (0.12.1). J'ai vu ça flask --helpmais je ne vois pas les routes ou les URL sur la page CLI
mrgnw
les itinéraires semblent être supprimés dans le flacon 1.1.2
Jerry Ji
5

Comme vous n'avez pas spécifié qu'il doit être exécuté en ligne de commande, ce qui suit pourrait facilement être retourné dans json pour un tableau de bord ou une autre interface non-ligne de commande. De toute façon, le résultat et la sortie ne devraient pas être mélangés du point de vue de la conception. C'est une mauvaise conception de programme, même s'il s'agit d'un tout petit programme. Le résultat ci-dessous pourrait alors être utilisé dans une application Web, une ligne de commande ou tout autre élément qui ingère json.

Vous n'avez pas non plus spécifié que vous deviez connaître la fonction python associée à chaque route, donc cela répond plus précisément à votre question initiale.

J'utilise ci-dessous pour ajouter moi-même la sortie à un tableau de bord de surveillance. Si vous voulez les méthodes d'itinéraire disponibles (GET, POST, PUT, etc.), vous devrez les combiner avec d'autres réponses ci-dessus.

La fonction repr () de Rule se charge de convertir les arguments requis dans la route.

def list_routes():
    routes = []

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

    return routes

La même chose en utilisant une compréhension de liste:

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

Exemple de sortie:

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

Si vous avez besoin d'accéder aux fonctions d'affichage elles-mêmes, au lieu de app.url_map, utilisezapp.view_functions .

Exemple de script:

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

Sortie de l'exécution du script ci-dessus:

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

route1
<function route1 at 0x128f1b9d8>

route2
<function route2 at 0x128f1ba60>

(Notez l'inclusion de la route "statique", qui est créée automatiquement par Flask.)

Mark Amery
la source
2

Vous pouvez afficher toutes les routes via flask shell en exécutant les commandes suivantes après avoir exporté ou défini la variable d'environnement FLASK_APP. flask shell app.url_map

Xerrex
la source
1

dans votre application flask, faites:

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