Was ist reverse () in Django

218

Wenn ich manchmal Django-Code lese, sehe ich in einigen Vorlagen reverse(). Ich bin nicht ganz sicher, was das ist, aber es wird zusammen mit HttpResponseRedirect verwendet. Wie und wann reverse()soll das verwendet werden?

Es wäre schön, wenn jemand eine Antwort mit einigen Beispielen geben würde ...

Lakesh
quelle
26
Bei einem gegebenen URL-Muster verwendet Django url (), um die richtige Ansicht auszuwählen und eine Seite zu generieren. Das heißt , url--> view name. Aber manchmal, wie bei der Umleitung, müssen Sie in die umgekehrte Richtung gehen und Django den Namen einer Ansicht geben, und Django generiert die entsprechende URL. Mit anderen Worten view name --> url. Das heißt reverse()(es ist die Umkehrung der URL-Funktion). Es mag transparenter erscheinen, es einfach zu nennen, generateUrlFromViewNameaber das ist zu lang und wahrscheinlich nicht allgemein genug: docs.djangoproject.com/de/dev/topics/http/urls/…
Eric
4
@neuronet Tolle Erklärung, danke. Dieser Name schien (und scheint) mir nicht intuitiv zu sein, was ich für eine schwere Sünde halte. Wer hasst keine unnötige Verschleierung?
Mike Nagetier
Dies ist ein typisches Beispiel für die Benennung, bei dem ein Aspekt einer Entität (z. B. eine Funktion) hervorgehoben wird, der dem Programmierer zu diesem Zeitpunkt in Anbetracht seines Kontexts am wichtigsten war, der jedoch im allgemeinen Kontext eines anderen Entwicklers nicht die nützlichste Option ist . Als Programmierer geraten wir oft in diese Falle - die Benennung ist für die Auffindbarkeit so wichtig, dass es sich lohnt, anzuhalten, über die verschiedenen Kontexte nachzudenken und den am besten geeigneten auszuwählen.
Cornel Masson

Antworten:

345

reverse()| Django-Dokumentation


Nehmen wir an, urls.pySie haben dies in Ihrem definiert:

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

In einer Vorlage können Sie dann auf diese URL verweisen als:

<!-- 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>

Dies wird wie folgt gerendert:

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

Angenommen, Sie möchten etwas Ähnliches in Ihrem tun views.py- z. B. Sie behandeln eine andere URL (nicht /foo/) in einer anderen Ansicht (nicht some_view) und möchten den Benutzer umleiten /foo/(häufig bei erfolgreicher Formularübermittlung).

Sie könnten einfach tun:

return HttpResponseRedirect('/foo/')

Aber was ist, wenn Sie die URL in Zukunft ändern möchten? Sie müssten Ihre urls.py und alle Verweise darauf in Ihrem Code aktualisieren . Dies verstößt gegen DRY (Don't Repeat Yourself) , die ganze Idee, nur einen Ort zu bearbeiten, was etwas ist, nach dem man streben muss.

Stattdessen können Sie sagen:

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

Dies durchsucht alle in Ihrem Projekt definierten URLs nach der mit dem Namen definierten URL url_nameund gibt die tatsächliche URL zurück /foo/.

Dies bedeutet, dass Sie auf die URL nur anhand ihres nameAttributs verweisen. Wenn Sie die URL selbst oder die Ansicht, auf die sie verweist, ändern möchten, können Sie dies tun, indem Sie nur eine Stelle bearbeiten urls.py.

Sense
quelle
2
Zu Ihrer Information, {{ url 'url_name' }}sollte {% url url_name %}in Django 1.4 oder früher sein. Dies wird sich in der nächsten Django-Version (1.5) ändern und sollte es dann sein {% url 'url_name' %}. Die Dokumente für das URL-Templatetag geben einige gute Informationen, wenn Sie ein wenig nach unten zum Abschnitt "Vorwärtskompatibilität"
scrollen
1
j_syk danke - ich mache @load url from future @ seit 1.3 herausgekommen und habe vergessen, dass es noch nicht die Standardeinstellung ist. Ich werde meine Antwort aktualisieren, damit sie nicht zu Unerfahrenen führt.
Sense
2
behoben - Ich denke, es wird als völlig akzeptabel angesehen, wenn Sie dumme Tippfehler in den Antworten anderer Leute selbst bearbeiten. Wenn Sie also mehr sehen, springen Sie einfach hinein :-)
scytale
3
Eine der subtilsten Antworten, die man auf dieser Seite finden kann.
Manas Chaturvedi
1
">>> aber was ist, wenn Sie die URL in Zukunft ändern möchten?" Best Practices 'und verlassen Sie das Chaos. TBH, wenn Sie in Zukunft die URLs ändern, führen Sie einfach einen globalen Find-Replace durch. Selbst diese Lösung (verwenden Sie url_name) ist anfällig für das Problem "Was ist, wenn Sie den url_name in Zukunft ändern möchten?" Ich programmiere seit über 5 Jahren in Django und muss den Bedarf noch decken url_reverse. Der beste Weg, mit solchen Kuriositäten umzugehen, besteht darin, sich zu weigern, sie zu benutzen.
Nehem
10

Dies ist eine alte Frage, aber hier ist etwas, das jemandem helfen könnte.

Aus den offiziellen Dokumenten:

Django bietet Tools zum Durchführen der URL-Umkehrung, die den verschiedenen Ebenen entsprechen, in denen URLs benötigt werden: In Vorlagen: Verwenden des URL-Vorlagen-Tags. Im Python-Code: Verwenden der Funktion reverse (). In höherwertigem Code für die Behandlung von URLs von Django-Modellinstanzen: Die Methode get_absolute_url ().

Z.B. in Vorlagen (URL-Tag)

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

Z.B. im Python-Code (mit der reverseFunktion)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
Kishy Nivas
quelle
1
brauche vollständige Beschreibung Chef
gebenJob
OP erwähnte ausdrücklich, dass er die Dokumente las, er brauchte eine Erklärung, nicht nur das Kopieren / Einfügen aus den Dokumenten.
RusI
8

Bestehende Antworten haben großartige Arbeit geleistet, um zu erklären, was diese reverse()Funktion in Django ist.

Ich hatte jedoch gehofft, dass meine Antwort ein anderes Licht auf das Warum werfen würde : Warum reverse()anstelle von anderen einfacheren, wohl pythonischeren Ansätzen beim Binden von Vorlagenansichten und was sind einige legitime Gründe für die Popularität dieser "Weiterleitung über" reverse() Muster "in der Django-Routing-Logik.

Ein wesentlicher Vorteil ist die umgekehrte Konstruktion einer URL, wie andere bereits erwähnt haben. Genau so, wie Sie {% url "profile" profile.id %}die URL aus der URL-Konfigurationsdatei Ihrer App generieren würden : z path('<int:profile.id>/profile', views.profile, name="profile").

Wie das OP jedoch festgestellt hat, wird die Verwendung von reverse()üblicherweise auch mit der Verwendung von kombiniert HttpResponseRedirect. Aber wieso?

Ich bin nicht ganz sicher, was das ist, aber es wird zusammen mit HttpResponseRedirect verwendet. Wie und wann soll dieses reverse () verwendet werden?

Beachten Sie Folgendes 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)
        ))

Und unser Minimum 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')
]

In der vote()Funktion wird der Code in unserem elseBlock reversezusammen mit HttpResponseRedirectdem folgenden Muster verwendet:

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

Dies bedeutet in erster Linie, dass wir die URL nicht fest codieren müssen (im Einklang mit dem DRY-Prinzip), sondern vor allem reverse()eine elegante Möglichkeit zum args=(question.id)Erstellen von URL-Zeichenfolgen bietet, indem Werte behandelt werden, die aus den Argumenten entpackt wurden ( wird von URLConfig behandelt). Angenommen, es questiongibt ein Attribut, iddas den Wert enthält 5. Die daraus erstellte URL reverse()lautet dann:

'/polls/5/results/'

In normalem Bindungscode für Vorlagenansichten verwenden wir HttpResponse()oder render()da diese normalerweise weniger Abstraktion beinhalten: Eine Ansichtsfunktion gibt eine Vorlage zurück:

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

In vielen legitimen Fällen der Umleitung ist es uns jedoch in der Regel wichtig, die URL aus einer Liste von Parametern zu erstellen. Dazu gehören Fälle wie:

  • Übermittlung des HTML-Formulars auf POSTAnfrage
  • Benutzeranmeldung nach Validierung
  • Setzen Sie das Passwort über JSON-Web-Token zurück

Bei den meisten handelt es sich um eine Umleitung und eine URL, die aus einer Reihe von Parametern besteht. Hoffe, dies ergänzt den bereits hilfreichen Thread der Antworten!

einziges Phantom
quelle
4

Die Funktion unterstützt das Trockenprinzip - stellt sicher, dass Sie keine URLs in Ihrer App fest codieren. Eine URL sollte an einem Ort und nur an einem Ort definiert werden - Ihre URL conf. Danach verweisen Sie wirklich nur noch auf diese Informationen.

Verwenden reverse()Sie diese Option, um die URL einer Seite anzugeben, entweder den Pfad zur Ansicht oder den Parameter page_name aus Ihrer URL conf. Sie würden es in Fällen verwenden, in denen es keinen Sinn macht, es in der Vorlage mit zu tun {% url 'my-page' %}.

Es gibt viele mögliche Stellen, an denen Sie diese Funktionalität verwenden können. Ich habe festgestellt, dass ich es verwende, wenn Benutzer in einer Ansicht umgeleitet werden (häufig nach der erfolgreichen Verarbeitung eines Formulars).

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

Sie können es auch beim Schreiben von Vorlagen-Tags verwenden.

Ein anderes Mal habe ich reverse()mit Modellvererbung gearbeitet. Ich hatte eine ListView für ein übergeordnetes Modell, wollte aber von einem dieser übergeordneten Objekte zur Detailansicht des zugehörigen untergeordneten Objekts gelangen. Ich get__child_url()habe dem Elternteil eine Funktion angehängt , die die Existenz eines Kindes identifiziert und die URL seiner Detailansicht mit zurückgegeben hat reverse().

Ashish Kumar Sahoo
quelle
2

Die vorhandenen Antworten sind ziemlich klar. Nur für den Fall, dass Sie nicht wissen, warum es aufgerufen wird reverse: Es wird ein URL-Name eingegeben und die tatsächliche URL angegeben. Dies ist umgekehrt, wenn Sie zuerst eine URL haben und dann einen Namen vergeben.

yyFred
quelle
1
Ich lerne gerade Django aus einem Tutorial (Django Girls). Es ist eine steile Lernkurve. Ich denke, der Name dieser Funktion ist schrecklich: "reservieren" ohne jegliche Qualifikation schlägt SEHR STARK vor, eine Liste oder einen String zu reservieren, was offensichtlich überhaupt nichts damit zu tun hat.
Mike Nagetier
@mikerodent Ich stimme dir vollkommen zu. Außerdem erklärt keine dieser Antworten, warum die Funktion als umgekehrt bezeichnet wird. Es ist so ein schlechter Name imo.
Soham Dongargaonkar
1

Mit reverse () wird das Django DRY-Prinzip eingehalten. Wenn Sie also die URL in Zukunft ändern, können Sie diese URL mit reverse (urlname) referenzieren.

AEROCODE
quelle