O Flask oferece suporte a expressões regulares em seu roteamento de URL?

100

Eu entendo que o Flask tem os conversores int, float e path, mas o aplicativo que estamos desenvolvendo tem padrões mais complexos em seus URLs.

Existe uma maneira de usar expressões regulares, como no Django?

Alistair
fonte

Respostas:

192

Mesmo que Armin me supere com uma resposta aceita, pensei em mostrar um exemplo abreviado de como implementei um matcher regex no Flask, apenas no caso de alguém querer um exemplo prático de como isso poderia ser feito.

from flask import Flask
from werkzeug.routing import BaseConverter

app = Flask(__name__)

class RegexConverter(BaseConverter):
    def __init__(self, url_map, *items):
        super(RegexConverter, self).__init__(url_map)
        self.regex = items[0]


app.url_map.converters['regex'] = RegexConverter

@app.route('/<regex("[abcABC0-9]{4,6}"):uid>-<slug>/')
def example(uid, slug):
    return "uid: %s, slug: %s" % (uid, slug)


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

este URL deve retornar com 200: http: // localhost: 5000 / abc0-foo /

este URL deve retornar com 404: http: // localhost: 5000 / abcd-foo /

Philip Southam
fonte
4
Mas isso significa que as expressões regulares são compiladas ou são avaliadas em tempo real?
Games Brainiac
1
Parece que a regex será avaliada diretamente no tempo de execução. Isso não deve ser problemático para aplicativos menores (ou aplicativos que reutilizam regex várias vezes, eu acho), já que os últimos padrões de regex são armazenados compilados na memória.
bbenne10
5
Como é que isso funciona? O padrão é definido como self.regex, mas onde a correspondência acontece?
Justin de
@Justin A correspondência acontece nos internos de Werkzeug Aqui e em algum lugar na definição de uma regra que não encontrei.
AlexLordThorsen
49

Você pode conectar conversores personalizados que correspondem a expressões arbitrárias: Conversor personalizado

from random import randrange
from werkzeug.routing import Rule, Map, BaseConverter, ValidationError

class BooleanConverter(BaseConverter):

    def __init__(self, url_map, randomify=False):
        super(BooleanConverter, self).__init__(url_map)
        self.randomify = randomify
        self.regex = '(?:yes|no|maybe)'

    def to_python(self, value):
        if value == 'maybe':
            if self.randomify:
                return not randrange(2)
            raise ValidationError()
        return value == 'yes'

    def to_url(self, value):
        return value and 'yes' or 'no'

url_map = Map([
    Rule('/vote/<bool:werkzeug_rocks>', endpoint='vote'),
    Rule('/vote/<bool(randomify=True):foo>', endpoint='foo')
], converters={'bool': BooleanConverter})
Armin Ronacher
fonte
Eu não entendo o que to_pythonsignifica
corvid
17

Você também pode escrever uma captura de todos os tipos de rota e fazer roteamento complexo dentro do método:

from flask import Flask
app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'], defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST'])
def catch_all(path):
    return 'You want path: %s' % path

if __name__ == '__main__':
    app.run()

Isso vai corresponder a qualquer pedido. Veja mais detalhes aqui: URL pega-tudo .

Zorayr
fonte
Eu tenho um erro, você poderia me dar algumas pistas? Arquivo "/app/catch_all.py", linha 234, em <module> @ app.route ('/ <path: path>', methods = ['GET']) Arquivo "/ usr / local / lib / python2. 7 / dist-packages / flask / app.py ", linha 1080, no arquivo decorador" /usr/local/lib/python2.7/dist-packages/flask/app.py ", linha 64, no arquivo wrapper_func" / usr / local / lib / python2.7 / dist-packages / flask / app.py ", linha 1051, em add_url_rule 'função de endpoint existente:% s'% endpoint) AssertionError: O mapeamento da função de visualização está substituindo uma função de endpoint existente: test
faísca