it-swarm-id.com

Bagaimana cara menggunakan url_for jika metode saya memiliki anotasi beberapa rute?

Jadi saya punya metode yang dapat diakses oleh beberapa rute:

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

Sekarang, bagaimana saya bisa memanggil url_for("foo") dan tahu bahwa saya akan mendapatkan rute pertama?

37
jiggy

Baik. Butuh beberapa mempelajari kode werkzeug.routing dan flask.helpers.url_for, tapi saya sudah menemukan jawabannya. Anda cukup mengubah endpoint untuk rute (dengan kata lain, Anda nama rute Anda)

@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"))

akan menghasilkan

jalur kanonik adalah/kanonik/jalur /, alternatifnya adalah/alternatif/jalur /

Ada kelemahan dari pendekatan ini. Flask selalu mengikat rute yang ditentukan terakhir ke titik akhir yang ditentukan secara implisit (foo dalam kode Anda). Coba tebak apa yang terjadi jika Anda mendefinisikan ulang titik akhir? Semua url_for('old_endpoint') Anda akan membuang werkzeug.routing.BuildError. Jadi, saya kira solusi yang tepat untuk seluruh masalah adalah mendefinisikan jalur kanonik yang terakhir dan name alternative:

""" 
   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"))
64
Nemoden

Aturan dalam Flask unik. Jika Anda mendefinisikan URL yang sama mutlak dengan fungsi yang sama, itu akan secara default bentrokan karena Anda melakukan sesuatu yang kami menghentikan Anda lakukan karena dari sudut pandang kami itu salah.

Ada satu alasan mengapa Anda ingin memiliki lebih dari satu URL ke titik akhir yang sama mutlak dan itu adalah kompatibilitas dengan aturan yang ada di masa lalu. Karena WZ0.8 dan Flask 0.8 Anda dapat secara eksplisit menentukan alias untuk rute:

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

Dalam hal ini jika pengguna meminta /index.html Flask akan secara otomatis mengeluarkan pengalihan secara permanen menjadi hanya /.

Itu tidak berarti suatu fungsi tidak dapat terikat ke lebih dari satu url, tetapi dalam hal ini Anda perlu mengubah titik akhir:

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

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

Atau sebagai alternatif:

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

Dalam hal ini, Anda dapat menentukan tampilan untuk kedua kalinya dengan nama yang berbeda. Namun ini adalah sesuatu yang umumnya Anda ingin hindari karena dengan demikian fungsi tampilan harus memeriksa request.endpoint untuk melihat apa yang disebut. Lebih baik lakukan sesuatu seperti ini:

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

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

def _index(alt):
    ...

Dalam kedua kasus ini, pembuatan URL adalah url_for('index') atau url_for('alt_index').

Anda juga dapat melakukan ini pada tingkat sistem perutean:

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

Dalam hal ini, url generation adalah url_for('index', alt=True) atau url_for('index', alt=False).

51
Armin Ronacher

Selain itu, bagi mereka yang menggunakan tangkapan semua rute yang dibangun dengan variabel: Labu akan membuat jalur url dengan benar jika url_for dilewatkan kamus yang berisi variabel.

Sebagai contoh...

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>

Ketika Anda mengklik tautan 'klik di sini', Anda akan diarahkan ke rute 'Posting/buat'.

0
vincent