2011-10-16 6 views

risposta

58

Ok. Ci sono voluti alcuni approfondimenti nel codice werkzeug.routing e flask.helpers.url_for, ma ho capito. Basta cambiare il endpoint di percorso (in altre parole, si nome il percorso)

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

produrrà

percorso canonico è/canonica/percorso /, alternativa è/alternativo/percorso/

C'è un inconveniente di questo approccio. Flask associa sempre l'ultima rotta definita al punto finale definito implicitamente (foo nel codice). Indovina cosa succede se ridefinisci l'endpoint? Tutto il tuo url_for('old_endpoint') genererà werkzeug.routing.BuildError. Quindi, credo che la soluzione giusta per l'intera questione sta definendo percorso canonico l'ultimo e nome alternativo:

""" 
    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")) 
+1

Che risposta approfondita e bella. Dammi una possibilità di verificare e la contrassegnerò come accettata. Dovresti forse inviarlo al popolo pocoo in modo che venga ufficialmente documentato. – jiggy

+0

Ok, ho avuto qualche problema con questo fino a quando non ho aggiornato a pallone 0.8 (non è riuscito con 0.7.2). Sembra anche che stia raccogliendo la prima annotazione, non l'ultima per me. In entrambi i casi, il parametro endpoint è la chiave. – jiggy

48

regole nel pallone sono unici. Se definisci lo stesso URL assoluto per la stessa funzione, per impostazione predefinita si scontrerà perché stai facendo qualcosa che ti impedisce di fare dal nostro punto di vista che è sbagliato.

C'è una ragione per cui si vorrebbe avere più di un URL per lo stesso endpoint assoluto e che è retrocompatibilità con una regola che esisteva in passato. Dal momento che WZ0.8 e Flask 0.8 è possibile specificare esplicitamente un alias per un percorso:

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

In questo caso, se l'utente richiede /index.html Flask emetterà automaticamente un redirect permanente ad appena /.

Ciò non significa una funzione non poteva essere destinata a più di un URL, però, ma in questo caso si avrebbe bisogno di modificare l'endpoint:

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

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

O in alternativa:

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

In questo caso è possibile definire una vista una seconda volta con un nome diverso. Tuttavia questo è qualcosa che generalmente si vuole evitare perché la funzione di visualizzazione dovrebbe controllare request.endpoint per vedere cosa viene chiamato. Invece meglio fare qualcosa di simile:

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

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

def _index(alt): 
    ... 

In entrambi questi casi generazione URL è url_for('index') o url_for('alt_index').

si può anche fare questo a livello di sistema di routing:

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

In questa generazione URL caso è url_for('index', alt=True) o url_for('index', alt=False).

+0

Sarebbe bello avere questo nella documentazione (o è già lì? Impossibile trovare). Il tuo ultimo esempio era esattamente ciò che è necessario per me. – aplavin

0

Inoltre, per coloro che utilizzano un catch di tutte le route costruite con variabili: Flask creerà correttamente il percorso url se url_for viene passato un dizionario contenente le variabili.

Per esempio ...

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> 

Quando si fa clic sul link 'clicca qui', si verrà indirizzati alla rotta "Post/Crea".

Problemi correlati