czym jest reverse () w Django


219

Kiedy czasami czytam kod django, widzę w niektórych szablonach reverse(). Nie jestem do końca pewien, co to jest, ale jest używane razem z HttpResponseRedirect. Jak i kiedy należy to reverse()wykorzystać?

Byłoby miło, gdyby ktoś dał odpowiedź z kilkoma przykładami ...


26
Biorąc pod uwagę wzorzec adresu URL, Django używa url (), aby wybrać odpowiedni widok i wygenerować stronę. Oznacza to, że url--> view name. Ale czasami, tak jak podczas przekierowywania, musisz iść w odwrotnym kierunku i podać Django nazwę widoku, a Django generuje odpowiedni adres URL. Innymi słowy view name --> url. To znaczy reverse()(jest odwrotnością funkcji url). Nazwanie go może wydawać się bardziej przejrzyste, generateUrlFromViewNameale jest to zbyt długie i prawdopodobnie niewystarczająco ogólne: docs.djangoproject.com/en/dev/topics/http/urls/…
— eric

4
@neuronet Świetne wyjaśnienie, dzięki. Ta nazwa wydawała mi się (i wydaje się) szczególnie nieintuicyjna, co uważam za poważny grzech. Kto nie nienawidzi niepotrzebnego zaciemniania?
— Mike

Jest to typowy przykład nazywania, który podkreśla jeden aspekt bytu (np. Funkcji), który w tym czasie był przede wszystkim w umyśle programisty, biorąc pod uwagę jego kontekst, ale nie jest najbardziej przydatną opcją w szerokim kontekście jakiegokolwiek innego programisty . Często wpadamy w tę pułapkę jako programiści - nazewnictwo jest tak ważne dla wykrywalności, że warto zatrzymać się i pomyśleć o różnych kontekstach i wybrać najbardziej odpowiedni.
— Cornel Masson

Odpowiedzi:


347

reverse()| Dokumentacja Django


Załóżmy, że urls.pyzdefiniowałeś to w swoim:

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

W szablonie możesz następnie odwołać się do tego adresu URL jako:

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

Będzie to renderowane jako:

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

Teraz powiedz, że chcesz zrobić coś podobnego w swoim views.py- np. Masz do czynienia z innym adresem URL (nie /foo/) w innym widoku (nie some_view) i chcesz przekierować użytkownika /foo/(często w przypadku pomyślnego przesłania formularza).

Możesz po prostu zrobić:

return HttpResponseRedirect('/foo/')

Ale co, jeśli chcesz zmienić adres URL w przyszłości? Będziesz musiał zaktualizować swoje urls.py i wszystkie odniesienia do niego w kodzie. To narusza DRY (Don't Repeat Yourself) , cały pomysł edytowania tylko jednego miejsca, do czego należy dążyć.

Zamiast tego możesz powiedzieć:

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

Przegląda wszystkie adresy URL zdefiniowane w projekcie pod kątem adresu URL zdefiniowanego za pomocą nazwy url_namei zwraca rzeczywisty adres URL /foo/.

Oznacza to, że odwołujesz się do adresu URL tylko za pomocą jego nameatrybutu - jeśli chcesz zmienić sam adres URL lub widok, którego dotyczy, możesz to zrobić, edytując tylko jedno miejsce - urls.py.


3
Do Twojej wiadomości, {{ url 'url_name' }}powinien być {% url url_name %}w Django 1.4 lub wcześniejszym. Zmieni się to w następnej wersji Django (1.5) i powinno być {% url 'url_name' %}. Dokumenty dotyczące szablonu
— adresu

1
j_syk dzięki - robiłem @load url z future @ odkąd 1.3 wyszło i zapomniałem, że to jeszcze nie jest domyślny. Zaktualizuję moją odpowiedź, aby nie zaskoczyła niedoświadczonego.
— scytale

2
naprawiono - myślę, że edytowanie głupich literówek w odpowiedziach innych osób jest całkowicie dopuszczalne, więc jeśli zobaczysz więcej, po prostu wskocz :-)
— scytale

3
Jedna z najbardziej subtelnych odpowiedzi, jakie można znaleźć na tej stronie.
— Manas Chaturvedi

1
„>>> ale co, jeśli chcesz zmienić adres URL w przyszłości”, tego rodzaju subtelności są przydatne przez 0,0001% czasu, a rozwiązanie jest dostarczane jak przydatna funkcja, a ludzie używają go tak, jakby to było „ najlepsze praktyki ”i zostaw bałagan. TBH, jeśli jeśli w przyszłości zmienisz adresy URL, po prostu wykonasz globalne wyszukiwanie-zamień. Nawet to rozwiązanie (użyj nazwy url) jest podatne na problem „co jeśli chcesz zmienić nazwę url w przyszłości?” Koduję w Django od ponad 5 lat i jeszcze nie spełniam wymagań url_reverse. Najlepszym sposobem radzenia sobie z tego rodzaju dziwactwami jest odmowa ich użycia.
— nehem

10

To stare pytanie, ale jest coś, co może komuś pomóc.

Z oficjalnych dokumentów:

Django zapewnia narzędzia do wykonywania odwracania adresów URL, które pasują do różnych warstw, w których potrzebne są adresy URL: W szablonach: Używanie tagu szablonu adresu URL. W kodzie Python: Korzystanie z funkcji reverse (). W kodzie wyższego poziomu związanym z obsługą adresów URL instancji modelu Django: metoda get_absolute_url ().

Na przykład. w szablonach (tag url)

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

Na przykład. w kodzie python (przy użyciu reversefunkcji)

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

1
potrzebuję pełnego opisu szefie
— dajJob

OP konkretnie wspomniał, że czytał dokumenty, potrzebował wyjaśnień, a nie tylko kopiowania / wklejania z dokumentów.
— RusI

8

Istniejące odpowiedzi świetnie spisały się wyjaśniając, co z tą reverse()funkcją w Django.

Miałem jednak nadzieję, że moja odpowiedź rzuci inne światło na to, dlaczego : dlaczego używać reverse()zamiast innych, bardziej prostych, prawdopodobnie bardziej pythonowych podejść w wiązaniu widoku szablonu, i jakie są uzasadnione powody popularności tego przekierowania za pośrednictwem reverse() wzorzec ”w logice routingu Django.

Jedną z kluczowych korzyści jest odwrotna konstrukcja adresu URL, jak wspomniali inni. Podobnie jak chcesz {% url "profile" profile.id %}wygenerować adres URL z pliku konfiguracyjnego adresu URL aplikacji: np path('<int:profile.id>/profile', views.profile, name="profile").

Ale, jak zauważył PO, użycie reverse()jest również często łączone z użyciem HttpResponseRedirect. Ale dlaczego?

Nie jestem do końca pewien, co to jest, ale jest używane razem z HttpResponseRedirect. Jak i kiedy ma być używana funkcja reverse ()?

Rozważ następujące kwestie 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)
        ))

A nasze minimalne 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')
]

W vote()funkcji kod w naszym elsebloku używa reversewraz z HttpResponseRedirectnastępującym wzorem:

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

To przede wszystkim oznacza, że ​​nie musimy kodować adresu URL na stałe (zgodnie z zasadą DRY), ale co bardziej istotne, reverse()zapewnia elegancki sposób konstruowania ciągów adresów URL poprzez obsługę wartości rozpakowanych z argumentów ( args=(question.id)jest obsługiwany przez URLConfig). Nałożony questionma atrybut, idktóry zawiera wartość 5, adres URL skonstruowany na podstawie reverse()będzie wtedy:

'/polls/5/results/'

W normalnym kodzie wiązania widoku szablonu używamy HttpResponse()lub, render()ponieważ zazwyczaj wymagają one mniej abstrakcji: jedna funkcja widoku zwraca jeden szablon:

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

Ale w wielu uzasadnionych przypadkach przekierowania zazwyczaj zależy nam na zbudowaniu adresu URL z listy parametrów. Obejmują one przypadki takie jak:

  • Przesyłanie formularza HTML za pośrednictwem POSTżądania
  • Potwierdzenie logowania użytkownika
  • Zresetuj hasło za pomocą tokenów internetowych JSON

Większość z nich wymaga przekierowania i adresu URL zbudowanego na podstawie zestawu parametrów. Mam nadzieję, że to dodaje do już pomocnego wątku odpowiedzi!


4

Ta funkcja obsługuje zasadę „sucha” - zapewniając, że nie kodujesz adresów URL w całej aplikacji. Adres URL powinien być zdefiniowany w jednym miejscu i tylko w jednym miejscu - twój adres URL. Potem tak naprawdę po prostu odwołujesz się do tych informacji.

Użyj, reverse()aby podać adres URL strony, podając ścieżkę do widoku lub parametr nazwa_strony z konf. Adresu URL. Używałbyś go w przypadkach, gdy nie ma sensu robić tego w szablonie {% url 'my-page' %}.

Istnieje wiele możliwych miejsc, w których możesz użyć tej funkcji. Korzystam z tego miejsca, gdy przekierowuję użytkowników w widoku (często po udanym przetworzeniu formularza) -

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

Możesz go również użyć podczas pisania znaczników szablonów.

Innym razem użyłem reverse()dziedziczenia modelu. Miałem ListView na modelu nadrzędnym, ale chciałem dostać się z jednego z tych obiektów nadrzędnych do DetailView powiązanego obiektu podrzędnego. I załączeniu get__child_url()funkcji do rodzica, który zidentyfikowano istnienie dziecka i wrócił url To DetailView użyciu reverse().



2

Istniejące odpowiedzi są dość jasne. Na wszelki wypadek, gdy nie wiesz, dlaczego się nazywa reverse: pobiera nazwę adresu URL i podaje rzeczywisty adres URL, co jest odwrotne do posiadania adresu URL, a następnie nadania mu nazwy.


1
Po prostu uczę się Django z samouczka (Django Girls). To stroma krzywa uczenia się. Myślę, że nazwa tej funkcji jest okropna: „Zarezerwuj” bez żadnych kwalifikacji BARDZO MOCNY sugeruje zarezerwowanie listy lub łańcucha, który oczywiście nie ma z tym nic wspólnego.
— Mike gryzoń

@mikerodent Całkowicie się z tobą zgadzam. Poza tym żadna z tych odpowiedzi nie wyjaśnia, dlaczego funkcja jest nazywana odwrotną. To takie złe imię imo.
— Soham Dongargaonkar

1

Funkcja reverse () służy do przestrzegania zasady DRY django DRY, tzn. Jeśli zmienisz adres URL w przyszłości, możesz odwoływać się do tego adresu URL za pomocą reverse (urlname).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.