Django: Przekieruj do poprzedniej strony po zalogowaniu


175

Próbuję zbudować prostą stronę internetową z funkcjonalnością logowania bardzo podobną do tej tutaj na SO. Użytkownik powinien mieć możliwość przeglądania witryny jako użytkownik anonimowy, a na każdej stronie będzie znajdował się link do logowania. Po kliknięciu łącza logowania użytkownik zostanie przeniesiony do formularza logowania. Po pomyślnym zalogowaniu użytkownik powinien zostać przeniesiony z powrotem na stronę, z której w pierwszej kolejności kliknął link logowania. Zgaduję, że muszę jakoś przekazać adres URL bieżącej strony do widoku obsługującego formularz logowania, ale tak naprawdę nie mogę go uruchomić.

EDYCJA: Rozgryzłem to. Połączyłem się z formularzem logowania, przekazując bieżącą stronę jako parametr GET, a następnie użyłem „next”, aby przekierować na tę stronę. Dzięki!

EDYCJA 2: Moje wyjaśnienie nie wydawało się jasne, więc zgodnie z żądaniem jest mój kod: Powiedzmy, że jesteśmy na stronie foo.html i nie jesteśmy zalogowani. Teraz chcielibyśmy mieć link na foo.html, który zawiera linki to login.html. Tam możemy się zalogować, a następnie zostajemy przekierowani z powrotem do foo.html. Link na foo.html wygląda następująco:

      <a href='/login/?next={{ request.path }}'>Login</a> 

Teraz napisałem niestandardowy widok logowania, który wygląda mniej więcej tak:

def login_view(request):
   redirect_to = request.REQUEST.get('next', '')
   if request.method=='POST':
      #create login form...
      if valid login credentials have been entered:
         return HttpResponseRedirect(redirect_to)  
   #...
   return render_to_response('login.html', locals())

I ważny wiersz w login.html:

<form method="post" action="./?next={{ redirect_to }}">

Więc tak, to prawie wszystko, mam nadzieję, że to wyjaśnia.


1
Myślę, że logowanie w Django załatwia to dla ciebie, czy to nie działa dla ciebie?
— Dominic Rodger

Odpowiedzi:


151

Nie musisz w tym celu tworzyć dodatkowego widoku, funkcjonalność jest już wbudowana.

Najpierw każda strona z łączem logowania musi znać aktualną ścieżkę, a najłatwiejszym sposobem jest dodanie preprosesora kontekstu żądania do settings.py (pierwsze 4 są domyślne), wtedy obiekt żądania będzie dostępny w każdym żądaniu:

settings.py:

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
)

Następnie dodaj szablon, do którego chcesz dodać link do logowania:

base.html:

<a href="{% url django.contrib.auth.views.login %}?next={{request.path}}">Login</a>

Spowoduje to dodanie argumentu GET do strony logowania, który wskazuje na bieżącą stronę.

Szablon logowania może być wtedy tak prosty:

rejestracja / login.html:

{% block content %}
<form method="post" action="">
  {{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}

47
Osobiście korzystam z tego rozwiązania, ale jedyną modyfikacją, jaką bym wprowadził, jest to, że nie powiedzie się, jeśli request.pathjest zerowe, więc robię to {% firstof request.path '/' %}w ten sposób, jeśli ścieżka żądania nie jest dostępna z jakiegoś powodu, użytkownik zostanie wysłany na stronę główną.
— jorelli

1
Próbuję zaimplementować Twoje rozwiązanie, ale gdy django.contrib.auth.views.login przekierowuje (po pomyślnym uwierzytelnieniu) wystąpienie użytkownika nie znajduje się w żądaniu, więc user.is_authenticated () zawsze zwraca False. Jakaś pomoc?
— juankysmith

3
Dodając do @jorelli, możesz użyć nazwanego adresu URL i <a href="{% url auth_login %}?next={% firstof request.path '/' %}">Login</a>zamiast tego zrobić .
— hobbes3

12
Trzeba też uważać na to, czy użytkownik zaloguje się już po wylogowaniu. Innymi słowy, nextbyłoby to coś podobnego /accounts/logout/i po zalogowaniu się użytkownika zostanie on natychmiast wylogowany z powrotem lol, a pętla będzie kontynuowana.
— hobbes3

2
Okazało się, że to zadziałało tylko wtedy, gdy dodałem następujące polecenie do formularza logowania w Django 1.5: <input type = "hidden" name = "next" value = "{{next}}" />
— Ellis Percival

28

Może to nie jest „najlepsza praktyka”, ale z powodzeniem stosowałem to wcześniej:

return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))

10
Ma to słaby punkt - część użytkowników / przeglądarek ma wyłączonego sędziego podającego
— Tomasz Zieliński

4
Istnieje również problem w przypadku, gdy użytkownik dociera do formularza, wypełnia informacje, a następnie przesyła. HTTP_REFERER jest wtedy adresem URL strony formularza, a nie adresem URL strony, z której przyszedł użytkownik.
— LaundroMat

25

Aby obsługiwać pełne adresy URL z parametrami / wartościami, których potrzebujesz:

?next={{ request.get_full_path|urlencode }}

zamiast tylko:

?next={{ request.path }}

Właściwie to nie jest dobry pomysł, ciąg zapytania będzie bardzo długi, jeśli masz zbyt wiele kliknięć
— dspjm

14

Wbudowane uwierzytelnianie Django działa tak, jak chcesz.

Ich strony logowania zawierają nextciąg zapytania, do którego należy powrócić po zalogowaniu.

Spójrz na http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required


4
Cóż, dekorator login_required działałby dobrze, ponieważ ustawia `` obok '' dowolnej strony, z której pochodzę, ale podczas korzystania z dekoratora anonimowi użytkownicy nie mogą przeglądać witryny, ponieważ będą od razu przekierowywani do formularza logowania. Myślę, że muszę tylko dowiedzieć się, jak ustawić wartość „next” w adresie URL strony, z której pochodzi użytkownik.
— jörg

1

Połączyłem się z formularzem logowania, przekazując bieżącą stronę jako parametr GET, a następnie użyłem „next”, aby przekierować na tę stronę. Dzięki!


1

Napotkałem ten sam problem. To rozwiązanie pozwala mi nadal używać ogólnego widoku logowania:

urlpatterns += patterns('django.views.generic.simple',
    (r'^accounts/profile/$', 'redirect_to', {'url': 'generic_account_url'}),
)

1

W registration/login.html(zagnieżdżone w templatesfolderze), jeśli wstawisz następujący wiersz, strona będzie wyglądać jak oryginalna strona logowania administratora Django:

{% include "admin/login.html" %}

Uwaga: plik powinien zawierać tylko powyższe wiersze.


-1

Zobacz dokumentację django dla views.login () , podajesz wartość 'next' (jako ukryte pole) w formularzu wejściowym, do którego ma nastąpić przekierowanie po pomyślnym zalogowaniu.


Tak, ale jak właściwie ustawić „obok” strony, z której pochodzę?
— jörg

-3

Ty też możesz to zrobić

<input type="hidden" name="text" value="{% url 'dashboard' %}" />

Zła odpowiedź, ale nazwa = 'next' wydaje się wykonalna, nie została przetestowana.
— WeizhongTu
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.