Uzyskaj listę wszystkich tras zdefiniowanych w aplikacji Flask

145

Mam złożoną aplikację internetową opartą na Flask. Istnieje wiele oddzielnych plików z funkcjami przeglądania. Ich adresy URL są definiowane za pomocą @app.route('/...')dekoratora. Czy istnieje sposób na uzyskanie listy wszystkich tras zadeklarowanych w mojej aplikacji? Może jest jakaś metoda, którą mogę wywołać na appobiekcie?

J-bob
źródło

Odpowiedzi:

152

Wszystkie trasy dla aplikacji są przechowywane, w app.url_mapktórej znajduje się instancja werkzeug.routing.Map. Możesz iterować po Ruleinstancjach za pomocą iter_rulesmetody:

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

Aby uzyskać więcej informacji, zobacz Wyświetlanie linków do utworzonych nowych stron internetowych .

Sean Vieira
źródło
Słodkie! Z wyjątkiem tego, że miałem problem z linią url = url_for(rule.endpoint). Właśnie dostałem ten błąd BuildError: ('DeleteEvent', {}, None). Zamiast tego, aby uzyskać adres URL, który właśnie zrobiłem url = rule.rule. Masz jakiś pomysł, dlaczego twoja metoda nie działa na mnie?
J-bob
@ J-bob - najprawdopodobniej trasa powiązana z DeleteEventma wymagany parametr - możesz albo określić ten przypadek w specjalnym przypadku, albo odfiltrować dowolne reguły, w którychlen(rule.arguments) > len(rule.defaults)
Sean Vieira
Myślę, że rozumiem. url_fornie można wygenerować adresu URL dla tej metody bez parametru, prawda? OK, ale wygląda na to, że moja metoda i tak działa, po prostu zachowuje tę część, jeśli adres URL jest parametrem. Dzięki!
J-bob
1
To świetny początek. Jakieś sugestie, jak utworzyć w pełni samodokumentującą się usługę internetową opartą na kolbach, w której wymienione są wszystkie parametry (takie jak? Spam = "jajka")? Być może te informacje można wydobyć z dokumentacji metody implementującej.
Leonid
2
Zamiast url_for(rule.endpoint)używać rule.ruletego lepiej, ponieważ rozwiązuj przypadki, w których masz więcej niż jedną trasę dla tej samej metody.
Zini,
84

Właśnie spotkałem to samo pytanie. Powyższe rozwiązanie jest zbyt złożone. Po prostu otwórz nową powłokę w swoim projekcie:

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

Pierwsza „ aplikacja ” to mój skrypt projektu: app.py , druga to nazwa mojej sieci.

(to rozwiązanie jest dla małej sieci z małą trasą)

Vi.Ci
źródło
1
To prawdopodobnie nie odpowiada bezpośrednio na pytanie. Ale z pewnością zasługuje na więcej głosów pochwalnych.
UltraInstinct
Ta odpowiedź jest świetna, ponieważ nie wymaga dodawania żadnego kodu do aplikacji. Użyłem go, aby uzyskać odpowiedź, której chciałem, w kilka sekund bez przebudowywania kodu.
joshdick
„Czy istnieje sposób na uzyskanie listy wszystkich tras zadeklarowanych w mojej aplikacji?” Myślę, że to odpowiada bezpośrednio na pytanie i powinno być akceptowaną odpowiedzią. Tak łatwo. Dzięki.
andho
2
Naprawdę nie widzę, jak to jest prostsze lub jaśniejsze niż zaakceptowana odpowiedź. Sugeruje to samo podejście, ale zajmuje więcej czasu, aby przejść do rzeczy i nie pokazuje, jak iterować Mapinstancję lub uzyskać dostęp do żadnej z właściwości zawartych w Ruleniej plików, bez których nie można zrobić nic użytecznego.
Mark Amery,
57

Tworzę metodę pomocniczą na moim 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

Rozwiązuje brakujący argument, budując fikcyjny zestaw opcji. Wynik wygląda następująco:

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

Następnie, aby go uruchomić:

python manage.py list_routes

Więcej informacji na temat manage.py checkout: http://flask-script.readthedocs.org/en/latest/

Jonathan
źródło
5
Powyższe działa bardzo dobrze. Po prostu zmień urllib.unquotena urllib.parse.unquotei print linena print(line)i działa również w Pythonie 3.x.
ściągaczka
1
To nie działa w przypadku argumentów niebędących ciągami znaków, zamiast tego zalecam użycie odpowiedzi Johna Jianga.
nico
42

Podobnie jak w przypadku odpowiedzi Jonathana, zdecydowałem się to zrobić. Nie widzę sensu używania url_for, ponieważ zepsuje się, jeśli twoje argumenty nie są ciągami, np. 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
źródło
32

Najwyraźniej od wersji 0.11 Flask ma wbudowany interfejs CLI . Jedno z wbudowanych poleceń wyświetla listę tras:

FLASK_APP='my_project.app' flask routes
theY4Kman
źródło
To jest absolutnie genialne!
pfabri
1
flask urlsdla mnie (0.12.1). Widziałem to, flask --helpale nie widzę tras ani adresów URL na stronie CLI
mrgnw
trasy wydają się być usunięte w kolbie 1.1.2
Jerry Ji
5

Ponieważ nie określono, że ma być uruchamiany z wiersza polecenia, następujące elementy można łatwo zwrócić w json dla pulpitu nawigacyjnego lub innego interfejsu innego niż wiersz poleceń. Rezultat i rezultat naprawdę nie powinny być mieszane z punktu widzenia projektu. To zły projekt programu, nawet jeśli jest to mały program. Poniższy wynik może następnie zostać użyty w aplikacji internetowej, wierszu polecenia lub czymkolwiek innym, co pobiera json.

Nie określiłeś również, że musisz znać funkcję Pythona powiązaną z każdą trasą, więc to dokładniej odpowiada na twoje pierwotne pytanie.

Używam poniżej, aby samodzielnie dodać dane wyjściowe do panelu monitorowania. Jeśli chcesz poznać dostępne metody tras (GET, POST, PUT itp.), Musisz połączyć je z innymi odpowiedziami powyżej.

Funkcja repr () reguły dba o konwersję wymaganych argumentów w trasie.

def list_routes():
    routes = []

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

    return routes

To samo przy użyciu rozumienia list:

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

Przykładowe dane wyjściowe:

{
  "routes": [
    "/endpoint1", 
    "/nested/service/endpoint2", 
    "/favicon.ico", 
    "/static/<path:filename>"
  ]
}
pocztowy
źródło
2

Jeśli chcesz uzyskać dostęp do samych funkcji widoku, zamiast tego app.url_mapużyj app.view_functions.

Przykładowy skrypt:

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

Wynik uruchomienia powyższego skryptu:

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

route1
<function route1 at 0x128f1b9d8>

route2
<function route2 at 0x128f1ba60>

(Zwróć uwagę na włączenie trasy „statycznej”, która jest tworzona automatycznie przez Flask).

Mark Amery
źródło
2

Możesz wyświetlić wszystkie trasy przez powłokę kolby, uruchamiając następujące polecenia po wyeksportowaniu lub ustawieniu zmiennej środowiskowej FLASK_APP. flask shell app.url_map

Xerrex
źródło
1

wewnątrz aplikacji flask wykonaj:

flask shell
>>> app.url_map
Map([<Rule '/' (OPTIONS, HEAD, GET) -> helloworld>,
 <Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>])
Nabaz Maaruf
źródło