cos'è reverse () in Django


220

Quando leggo il codice django a volte, vedo in alcuni modelli reverse(). Non sono del tutto sicuro di cosa si tratti, ma viene utilizzato insieme a HttpResponseRedirect. Come e quando reverse()dovrebbe essere usato?

Sarebbe bello se qualcuno desse una risposta con alcuni esempi ...


27
Dato uno schema url, Django usa url () per scegliere la vista giusta e generare una pagina. Cioè, url--> view name. Ma a volte, come durante il reindirizzamento, è necessario andare nella direzione opposta e dare a Django il nome di una vista e Django genera l'URL appropriato. In altre parole, view name --> url. Cioè, reverse()(è il contrario della funzione url). Potrebbe sembrare più trasparente chiamarlo, generateUrlFromViewNamema è troppo lungo e probabilmente non abbastanza generale: docs.djangoproject.com/en/dev/topics/http/urls/…
eric

4
@neuronet Grande spiegazione, grazie. Questo nome mi è sembrato (e sembra) particolarmente non intuitivo, che ritengo un grave peccato. Chi non odia l'offuscamento inutile?
mike rodent,

Questo è un tipico esempio di denominazione che enfatizza un aspetto di un'entità (ad es. Una funzione) che era principalmente nella mente del programmatore in quel momento, dato il suo contesto, ma non è l'opzione più utile nel vasto contesto di qualsiasi altro sviluppatore . Spesso cadiamo in questa trappola come programmatori: la denominazione è così importante per la rilevabilità, vale la pena fermarsi e pensare ai diversi contesti e scegliere quello più appropriato.
Cornel Masson,

Risposte:


349

reverse()| Documentazione Django


Supponiamo che nel tuo urls.pytu abbia definito questo:

url(r'^foo$', some_view, name='url_name'),

In un modello è quindi possibile fare riferimento a questo URL come:

<!-- django <= 1.4 -->
<a href="{% url url_name %}">link which calls some_view</a>

<!-- django >= 1.5 or with {% load url from future %} in your template -->
<a href="{% url 'url_name' %}">link which calls some_view</a>

Questo sarà reso come:

<a href="/foo/">link which calls some_view</a>

Ora dì che vuoi fare qualcosa di simile nel tuo views.py- ad esempio stai gestendo un altro URL (non /foo/) in un'altra vista (non some_view) e vuoi reindirizzare l'utente a /foo/(spesso il caso in caso di invio del modulo riuscito).

Potresti semplicemente fare:

return HttpResponseRedirect('/foo/')

Ma cosa succede se si desidera modificare l'URL in futuro? Dovresti aggiornare il tuo urls.py e tutti i riferimenti ad esso nel tuo codice. Questo viola DRY (Don't Repeat Yourself) , l'idea di modificare un solo posto, che è qualcosa per cui lottare.

Invece, puoi dire:

from django.urls import reverse
return HttpResponseRedirect(reverse('url_name'))

Questo controlla tutti gli URL definiti nel progetto per l'URL definito con il nome url_namee restituisce l'URL effettivo /foo/.

Ciò significa che ti riferisci all'URL solo per il suo nameattributo - se vuoi cambiare l'URL stesso o la vista a cui si riferisce puoi farlo modificando un solo posto - urls.py.


3
Cordiali saluti, {{ url 'url_name' }}dovrebbe essere {% url url_name %}in Django 1.4 o precedenti. Questo cambierà nella prossima versione di Django (1.5) e quindi dovrebbe esserlo {% url 'url_name' %}. I documenti per la templatetag dell'URL forniscono alcune buone informazioni se scorri un po 'verso il basso fino alla sezione "compatibilità in avanti"
j_syk,

1
grazie j_syk - sto facendo @load url dal futuro @ da quando 1.3 è uscito e ho dimenticato che non è ancora l'impostazione predefinita. Aggiornerò la mia risposta in modo che non inciampi inesperti.
scytale,

2
risolto - Penso che sia considerato totalmente accettabile per te modificare te stesso stupidi errori di risposta nelle altre persone, quindi se vedi di più basta saltare dentro :-)
scytale

3
Una delle risposte più sottili che si possano trovare su questo sito.
Manas Chaturvedi,

1
">>> ma cosa succede se si desidera modificare l'URL in futuro", questo tipo di sottigliezze che sono utili sullo 0,0101% delle volte e la soluzione viene spedita come una funzionalità utile e le persone lo usano come se lo fossero " migliori pratiche "e lasciare il pasticcio. TBH se quando si cambiano gli URL in futuro, si esegue semplicemente una ricerca-sostituzione globale. Anche questa soluzione (usa url_name) è soggetta al problema di "cosa succede se si desidera modificare url_name in futuro?" Ho programmato in Django per oltre 5 anni e ancora per soddisfare la necessità url_reverse. Il modo migliore per affrontare questo tipo di stranezze è rifiutarsi di usarle.
Nehem,

10

Questa è una vecchia domanda, ma ecco qualcosa che potrebbe aiutare qualcuno.

Dai documenti ufficiali:

Django fornisce strumenti per eseguire l'inversione degli URL che corrispondono ai diversi livelli in cui sono necessari gli URL: Nei modelli: utilizzo del tag del modello url. Nel codice Python: utilizzo della funzione reverse (). Nel codice di livello superiore relativo alla gestione degli URL delle istanze del modello Django: il metodo get_absolute_url ().

Per esempio. nei modelli (tag url)

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

Per esempio. in codice Python (usando la reversefunzione)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

1
bisogno di una descrizione completa boss
GiveJob

OP ha menzionato specificamente che ha letto i documenti, aveva bisogno di spiegazioni, non solo di copia / incolla dai documenti.
RusI

8

Le risposte esistenti fatto un ottimo lavoro a spiegare la cosa di questa reverse()funzione nel Django.

Tuttavia, speravo che la mia risposta gettasse una luce diversa sul perché : perché usare reverse()al posto di altri approcci più semplici, probabilmente più pitonici nel binding della vista template, e quali sono alcuni motivi legittimi per la popolarità di questo "reindirizzamento via reverse() pattern "nella logica di routing di Django.

Un vantaggio chiave è la costruzione inversa di un url, come altri hanno già detto. Proprio come utilizzeresti {% url "profile" profile.id %}per generare l'URL dal file di configurazione dell'URL della tua app: ad es path('<int:profile.id>/profile', views.profile, name="profile").

Ma come hanno notato gli OP, l'uso di reverse()è anche comunemente combinato con l'uso di HttpResponseRedirect. Ma perché?

Non sono del tutto sicuro di cosa si tratti, ma viene utilizzato insieme a HttpResponseRedirect. Come e quando dovrebbe essere usato questo reverse ()?

Considera quanto segue views.py:

from django.http import HttpResponseRedirect
from django.urls import reverse

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected = question.choice_set.get(pk=request.POST['choice'])
    except KeyError:
        # handle exception
        pass
    else:
        selected.votes += 1
        selected.save()
        return HttpResponseRedirect(reverse('polls:polls-results',
                                    args=(question.id)
        ))

E il nostro minimo urls.py:

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('<int:question_id>/results/', views.results, name='polls-results'),
    path('<int:question_id>/vote/', views.vote, name='polls-vote')
]

Nella vote()funzione, il codice nel nostro elseblocco utilizza reverseinsieme HttpResponseRedirectal seguente modello:

HttpResponseRedirect(reverse('polls:polls-results',
                                        args=(question.id)

In primo luogo, ciò significa che non è necessario codificare l'URL (coerentemente con il principio DRY), ma soprattutto, reverse()fornisce un modo elegante per costruire stringhe URL gestendo i valori decompressi dagli argomenti ( args=(question.id)è gestito da URLConfig). Supponiamo che questionabbia un attributo idche contenga il valore 5, l'URL creato da reverse()sarebbe quindi:

'/polls/5/results/'

Nel normale codice di associazione vista modello, utilizziamo HttpResponse()o render()poiché in genere comportano meno astrazioni: una funzione vista che restituisce un modello:

def index(request):
    return render(request, 'polls/index.html') 

Ma in molti casi legittimi di reindirizzamento, in genere ci preoccupiamo di costruire l'URL da un elenco di parametri. Questi includono casi come:

  • Invio di moduli HTML tramite POSTrichiesta
  • Post-convalida del login utente
  • Reimpostazione della password tramite token Web JSON

La maggior parte di questi comporta una qualche forma di reindirizzamento e un URL creato attraverso una serie di parametri. Spero che questo si aggiunga al già utile thread di risposte!


4

La funzione supporta il principio dry, assicurandoti di non codificare gli URL in tutta l'app. Un url dovrebbe essere definito in un unico posto e in un solo posto: l'url conf. Dopo di che stai davvero facendo riferimento a tali informazioni.

Utilizzare reverse()per fornire l'URL di una pagina, dato il percorso della vista o il parametro page_name dalla configurazione dell'URL. Lo useresti nei casi in cui non ha senso farlo nel modello con {% url 'my-page' %}.

Ci sono molti posti possibili in cui potresti usare questa funzionalità. Un posto che ho scoperto che lo uso è quando reindirizza gli utenti in una vista (spesso dopo l'elaborazione corretta di un modulo) -

return HttpResponseRedirect(reverse('thanks-we-got-your-form-page'))

È inoltre possibile utilizzarlo quando si scrivono tag modello.

Un'altra volta che ho usato è reverse()stata l'eredità del modello. Avevo un ListView su un modello genitore, ma volevo passare da uno di questi oggetti genitore al DetailView dell'oggetto figlio associato. Ho collegato una get__child_url()funzione al genitore che ha identificato l'esistenza di un figlio e ha restituito l'URL di DetailView utilizzando reverse().



2

Le risposte esistenti sono abbastanza chiare. Nel caso in cui non si conosca il motivo per cui viene chiamato reverse: prende un input di un nome url e fornisce l'URL effettivo, che è il contrario di avere prima un url e quindi dargli un nome.


1
Sto solo imparando Django da un tutorial (Django Girls). È una curva di apprendimento ripida. Penso che il nome di questa funzione sia terribile: "riservare" senza alcuna qualifica suggerisce MOLTO FORTE di riservare un elenco o una stringa, che ovviamente non ha nulla a che fare con esso.
mike rodent,

@mikerodent Sono completamente d'accordo con te. Inoltre, nessuna di queste risposte spiega perché la funzione è chiamata inversa. È un brutto nome imo.
Soham Dongargaonkar,

1

Il reverse () viene utilizzato per aderire al principio DRY di django, ovvero se in futuro si modifica l'URL, è possibile fare riferimento a tale url utilizzando reverse (urlname).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.