Obter lista de todas as rotas definidas no aplicativo Flask

145

Eu tenho um aplicativo Web complexo baseado em Flask. Existem muitos arquivos separados com funções de visualização. Seus URLs são definidos com o @app.route('/...')decorador. Existe uma maneira de obter uma lista de todas as rotas que foram declaradas em todo o meu aplicativo? Talvez haja algum método que eu possa chamar no appobjeto?

J-bob
fonte

Respostas:

152

Todas as rotas para um aplicativo são armazenadas nas app.url_mapquais é uma instância werkzeug.routing.Map. Você pode iterar sobre as Ruleinstâncias usando o 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 Exibir links para novas páginas da web criadas para um pouco mais de informação.

Sean Vieira
fonte
Doce! Exceto que eu tive um problema com a linha url = url_for(rule.endpoint). Acabei de receber este erro BuildError: ('DeleteEvent', {}, None). Em vez disso, para obter o URL que acabei de receber url = rule.rule. Alguma idéia de por que seu método não funciona para mim?
J-prumo
@ J-bob - muito provavelmente a rota associada DeleteEventtem um exigido parâmetro - você pode especial caso que um ou filtrar qualquer regras ondelen(rule.arguments) > len(rule.defaults)
Sean Vieira
Oh, eu acho que entendi. url_fornão pode gerar o URL para esse metid sem um parâmetro, certo? OK, mas parece que meu método funciona de qualquer maneira, apenas mantém essa parte se a URL como parâmetro. Obrigado!
J-prumo
1
Este é um grande começo. Alguma sugestão de como criar um serviço da Web baseado em balão totalmente auto-documentável, onde todos os parâmetros (como? Spam = "ovos") estão listados? Talvez essa informação possa ser extraída de uma doutrina de um método de implementação.
Leonid
2
Em vez de usar, url_for(rule.endpoint)use rule.rulemuito melhor porque resolverá casos em que você tenha mais de uma rota para o mesmo método.
Zini
82

Acabei de encontrar a mesma pergunta. A solução acima é muito complexa. Basta abrir um novo shell no seu projeto:

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

O primeiro ' app ' é o script do meu projeto: app.py , outro é o nome da minha web.

(esta solução é para web pequena com uma pequena rota)

Vi.Ci
fonte
1
Provavelmente isso não responde diretamente à pergunta. Mas com certeza merece muitos mais votos positivos.
UltraInstinct
Esta resposta é ótima por não exigir que você adicione nenhum código ao seu aplicativo. Usei-o para obter a resposta que queria em segundos, sem reconstruir meu código.
joshdick
"Existe uma maneira de obter uma lista de todas as rotas que foram declaradas em todo o meu aplicativo?" Acho que isso responde diretamente à pergunta e deve ser a resposta aceita. Tão fácil. Obrigado.
andho 8/09/18
2
Eu realmente não vejo como isso é mais simples ou mais claro que a resposta aceita. Ele está sugerindo a mesma abordagem, mas leva mais tempo para chegar ao ponto e não mostra como iterar sobre a Mapinstância ou acessar qualquer uma das propriedades dos Rules que ela contém, sem as quais você não pode realmente fazer nada útil.
Mark Amery
57

Eu faço um método auxiliar no meu 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

Ele resolve o argumento que falta, criando um conjunto fictício de opções. A saída se parece com:

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

Então, para executá-lo:

python manage.py list_routes

Para mais informações sobre o checkout manage.py: http://flask-script.readthedocs.org/en/latest/

Jonathan
fonte
5
O acima funciona muito bem. Apenas mude urllib.unquotepara urllib.parse.unquotee print linepara print(line)e também funciona no python 3.x.
Rd3
1
Isso não funciona para argumentos não-string, eu recomendo usar a resposta de John Jiang.
Nico
42

Semelhante à resposta de Jonathan, optei por fazer isso. Eu não vejo o ponto de usar url_for, pois ele será interrompido se seus argumentos não forem string, por exemplo, 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
fonte
31

Aparentemente, desde a versão 0.11, o Flask possui uma CLI integrada . Um dos comandos internos lista as rotas:

FLASK_APP='my_project.app' flask routes
theY4Kman
fonte
Isso é absolutamente brilhante!
pfabri
1
flask urlspara mim (0.12.1). Viu que no flask --help, mas não vejo rotas ou urls na página CLI
mrgnw
rotas parecem ter sido removidas no balão 1.1.2
Jerry Ji
5

Como você não especificou que ele deve ser executado na linha de comandos, o seguinte poderia ser facilmente retornado em json para um painel ou outra interface que não seja da linha de comandos. O resultado e a saída realmente não devem ser misturados da perspectiva do design. É um design de programa ruim, mesmo que seja um programa minúsculo. O resultado abaixo pode ser usado em um aplicativo Web, linha de comando ou qualquer outra coisa que ingira json.

Você também não especificou que precisava conhecer a função python associada a cada rota, portanto, isso responde com mais precisão à sua pergunta original.

Eu uso abaixo para adicionar a saída a um painel de monitoramento. Se você quiser os métodos de rota disponíveis (GET, POST, PUT etc.), será necessário combiná-lo com outras respostas acima.

O repr () da regra cuida da conversão dos argumentos necessários na rota.

def list_routes():
    routes = []

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

    return routes

A mesma coisa usando uma compreensão de lista:

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

Saída de amostra:

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

Se você precisar acessar as funções de exibição, então, em vez de app.url_map, use app.view_functions.

Script de exemplo:

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

Saída da execução do script acima:

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

route1
<function route1 at 0x128f1b9d8>

route2
<function route2 at 0x128f1ba60>

(Observe a inclusão da rota "estática", criada automaticamente pelo Flask.)

Mark Amery
fonte
2

Você pode visualizar todas as rotas através do shell do balão executando os seguintes comandos após exportar ou definir a variável de ambiente FLASK_APP. flask shell app.url_map

Xerrex
fonte
1

dentro do seu aplicativo de balão, faça:

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