Подтвердить что ты не робот

Как использовать url_for, если мой метод имеет несколько аннотаций маршрута?

Итак, у меня есть метод, доступный несколькими путями:

@app.route("/canonical/path/")
@app.route("/alternate/path/")
def foo():
    return "hi!"

Теперь, как я могу позвонить url_for("foo") и узнать, что я получу первый маршрут?

4b9b3361

Ответ 1

Ok. Потребовалось некоторое обсуждение в коде werkzeug.routing и flask.helpers.url_for, но я понял. Вы просто изменяете endpoint для маршрута (другими словами, вы имя ваш маршрут)

@app.route("/canonical/path/", endpoint="foo-canonical")
@app.route("/alternate/path/")
def foo():
    return "hi!"

@app.route("/wheee")
def bar():
    return "canonical path is %s, alternative is %s" % (url_for("foo-canonical"), url_for("foo"))

создаст

канонический путь/канонический/путь/, альтернатива -/alternate/path/

Существует недостаток такого подхода. Флажок всегда привязывает последний определенный маршрут к конечной точке, определенной неявно (foo в вашем коде). Угадайте, что произойдет, если вы переопределите конечную точку? Все ваши url_for('old_endpoint') будут бросать werkzeug.routing.BuildError. Итак, я думаю, правильным решением для всей проблемы является определение канонического пути последней и альтернативной альтернативы:

""" 
   since url_for('foo') will be used for canonical path
   we don't have other options rather then defining an endpoint for
   alternative path, so we can use it with url_for
"""
@app.route('/alternative/path', endpoint='foo-alternative')
""" 
   we dont wanna mess with the endpoint here - 
   we want url_for('foo') to be pointing to the canonical path
"""
@app.route('/canonical/path') 
def foo():
    pass

@app.route('/wheee')
def bar():
    return "canonical path is %s, alternative is %s" % (url_for("foo"), url_for("foo-alternative"))

Ответ 2

Правила в колбе уникальны. Если вы определите абсолютный одинаковый URL-адрес для одной и той же функции, он по умолчанию столкнется, потому что вы делаете то, что мы мешаем вам делать, поскольку с нашей точки зрения это неверно.

Есть одна причина, по которой вы хотели бы иметь более одного URL-адреса для абсолютной конечной точки, и это обратная совместимость с правилом, существовавшим в прошлом. Начиная с WZ0.8 и Flask 0.8 вы можете явно указать псевдоним для маршрута:

@app.route('/')
@app.route('/index.html', alias=True)
def index():
    return ...

В этом случае, если пользователь запрашивает /index.html, флажок автоматически выдаст постоянную переадресацию только /.

Это не означает, что функция не может быть привязана к более чем одному URL-адресу, но в этом случае вам нужно будет изменить конечную точку:

@app.route('/')
def index():
    ...

app.add_url_rule('/index.html', view_func=index, endpoint='alt_index')

Или, альтернативно:

@app.route('/')
@app.route('/index.html', endpoint='alt_index')
def index():
    ...

В этом случае вы можете определить представление во второй раз под другим именем. Однако это то, чего вы обычно хотите избежать, потому что тогда функция просмотра должна будет проверить request.endpoint, чтобы увидеть, что называется. Вместо этого лучше сделайте что-нибудь вроде этого:

@app.route('/')
def index():
    return _index(alt=False)

@app.route('/index.html')
def alt_index():
    return _index(alt=True)

def _index(alt):
    ...

В обоих случаях генерация URL-адресов составляет url_for('index') или url_for('alt_index').

Вы также можете сделать это на уровне системы маршрутизации:

@app.route('/', defaults={'alt': False})
@app.route('/index.html', defaults={'alt': True})
def index(alt):
    ...

В этом случае генерация url url_for('index', alt=True) или url_for('index', alt=False).

Ответ 3

Кроме того, для тех, кто использует весь маршрут, построенный с переменными: Flask будет правильно создавать URL-адрес, если url_for передается словарь, содержащий переменные.

Например...

app.py:

app.route('/<path:pattern1>')
app.route('/<path:pattern1>/<path:pattern2>')
def catch_all(pattern1, pattern2=None):
    return render_template('template.html', p1=pattern1, p2=pattern2)

app.route('/test')
def test_routing:
    args = {'pattern1': 'Posts', 'pattern2': 'create'}
    return render_template('test.html', args=args)

test.html:

<a href="{{url_for('catch_all', **args)}}">click here</a>

Когда вы нажмете ссылку "нажмите здесь", вы будете перенаправлены на маршрут "Сообщения/создать".