it-swarm.com.de

Django: Signal, wenn sich der Benutzer anmeldet?

In meiner Django-App muss ich anfangen, einige periodische Hintergrundjobs auszuführen, wenn sich ein Benutzer anmeldet, und seine Ausführung beenden, wenn sich der Benutzer abmeldet. Ich suche also nach einem eleganten Weg

  1. von einem Benutzer anmelden/abmelden
  2. benutzeranmeldestatus abfragen

Aus meiner Sicht wäre die ideale Lösung

  1. ein Signal, das von jedem Django.contrib.auth.views.login und ... views.logout gesendet wird
  2. eine Methode Django.contrib.auth.models.User.is_logged_in(), analog zu ... User.is_active() oder ... User.is_authenticated()

Django 1.1.1 hat das nicht und ich zögere, die Quelle zu patchen und hinzuzufügen (ich bin sowieso nicht sicher, wie das geht).

Als vorübergehende Lösung habe ich dem UserProfile-Modell ein boolesches is_logged_in-Feld hinzugefügt, das standardmäßig deaktiviert ist. Das Feld wird gesetzt, wenn der Benutzer zum ersten Mal die Zielseite (definiert durch LOGIN_REDIRECT_URL = '/') besucht und in nachfolgenden Anforderungen abgefragt wird. Ich habe es zu UserProfile hinzugefügt, sodass ich das eingebaute Benutzermodell nicht nur zu diesem Zweck ableiten und anpassen muss.

Ich mag diese Lösung nicht. Wenn der Benutzer explizit auf die Schaltfläche zum Abmelden klickt, kann ich die Markierung löschen, aber meistens verlassen Benutzer die Seite oder schließen den Browser. Das Löschen der Flagge in diesen Fällen erscheint mir nicht direkt. Abgesehen davon (das ist eher Datenmodell-Klarheit, aber nicht pingelig), gehört is_logged_in nicht zum UserProfile, sondern zum User-Modell.

Kann sich jemand alternative Ansätze vorstellen?

70
ssc

Sie können ein Signal wie dieses verwenden (ich setze mein in models.py ein)

from Django.contrib.auth.signals import user_logged_in


def do_stuff(sender, user, request, **kwargs):
    whatever...

user_logged_in.connect(do_stuff)

Siehe Django-Dokumente: https://docs.djangoproject.com/de/dev/ref/contrib/auth/#module-Django.contrib.auth.signals und hier http: //docs.djangoproject. de/de/dev/topics/signale/

133
PhoebeB

Eine Option könnte sein, die Login-/Logout-Ansichten von Django mit Ihren eigenen Ansichten zu versehen. Zum Beispiel:

from Django.contrib.auth.views import login, logout

def my_login(request, *args, **kwargs):
    response = login(request, *args, **kwargs)
    #fire a signal, or equivalent
    return response

def my_logout(request, *args, **kwargs):
    #fire a signal, or equivalent
    return logout(request, *args, **kwargs)

Sie verwenden diese Ansichten dann in Ihrem Code anstelle von Django's und voila.

In Bezug auf die Abfrage des Anmeldestatus ist es ziemlich einfach, wenn Sie auf das Anforderungsobjekt zugreifen können. Überprüfen Sie einfach das Benutzerattribut der Anforderung, um zu sehen, ob es sich um einen registrierten oder anonymen Benutzer handelt, und um Bingo. So zitieren Sie die Django-Dokumentation :

if request.user.is_authenticated():
    # Do something for logged-in users.
else:
    # Do something for anonymous users.

Wenn Sie keinen Zugriff auf das Anforderungsobjekt haben, wird es schwierig sein, festzustellen, ob der aktuelle Benutzer angemeldet ist.

Bearbeiten:

Leider können Sie nie User.is_logged_in()-Funktionalität erhalten - dies ist eine Einschränkung des HTTP-Protokolls. Wenn Sie einige Annahmen treffen, können Sie jedoch möglicherweise an das herangehen, was Sie möchten.

Erstens, warum können Sie diese Funktionalität nicht erhalten? Nun, Sie können den Unterschied nicht erkennen, ob jemand den Browser geschlossen hat oder jemand eine Weile auf einer Seite verbringt, bevor er einen neuen Browser abruft. Es gibt keine Möglichkeit, über HTTP zu informieren, wenn jemand die Site tatsächlich verlässt oder den Browser schließt.

Sie haben also zwei Möglichkeiten, die nicht perfekt sind:

  1. Verwenden Sie das unload-Ereignis von Javascript, um festzustellen, wann ein Benutzer eine Seite verlässt. Sie müssen jedoch eine sorgfältige Logik schreiben, um sicherzustellen, dass Sie einen Benutzer nicht abmelden, obwohl er noch auf der Ihrer-Site navigiert.
  2. Aktivieren Sie das Logout-Signal, wenn sich ein Benutzer anmeldet, nur um sicherzugehen. Erstellen Sie außerdem einen Cron-Job, der relativ häufig ausgeführt wird, um abgelaufene Sitzungen zu löschen. Wenn eine abgelaufene Sitzung gelöscht wird, überprüfen Sie, ob der Benutzer der Sitzung (wenn er nicht anonym ist) keine aktiven Sitzungen mehr hat.

Diese Lösungen sind unordentlich und nicht ideal, aber sie sind leider das Beste, was Sie tun können.

13
ShZ

Neben der @PhoebeB-Antwort: Können Sie auch @receiver-Dekorator folgendermaßen verwenden:

from Django.contrib.auth.signals import user_logged_in
from Django.dispatch import receiver

@receiver(user_logged_in)
def post_login(sender, user, request, **kwargs):
    ...do your stuff..`

Und wenn Sie es in signals.py in Ihrem Anwendungsverzeichnis ablegen, fügen Sie Folgendes zu app.py hinzu:

def ready(self):
    import app_name.signals`
7
bershika

Das Ableiten der Abmeldung, anstatt dass sie explizit auf eine Schaltfläche geklickt werden (was keiner tut), bedeutet, dass eine Leerlaufzeit gewählt wird, die "Abgemeldet" entspricht. phpMyAdmin verwendet einen Standardwert von 15 Minuten, einige Banking-Sites verwenden nur 5 Minuten.

Am einfachsten implementieren Sie dies, indem Sie die Lebensdauer des Cookies ändern. Sie können dies für Ihre gesamte Website tun, indem Sie settings.SESSION_COOKIE_AGE angeben. Alternativ können Sie es auf Benutzerbasis (basierend auf beliebigen Kriterien) ändern, indem Sie HttpResponse.setcookie() verwenden. Sie können diesen Code zentralisieren, indem Sie Ihre eigene Version von render_to_response() erstellen und die Gültigkeitsdauer für jede Antwort festlegen.

1
Peter Rowell

Die einzige zuverlässige Methode (die auch erkennt, wenn der Benutzer den Browser geschlossen hat) besteht darin, jedes last_request-Feld jedes Mal zu aktualisieren, wenn der Benutzer eine Seite lädt.

Sie können auch eine periodische AJAX - Anforderung haben, die den Server alle x Minuten pingt, wenn der Benutzer eine Seite geöffnet hat.

Sie haben dann einen einzigen Hintergrundjob, der eine Liste der letzten Benutzer abruft, Jobs für sie erstellt und die Jobs für Benutzer löscht, die nicht in dieser Liste vorhanden sind.

1
Joel L

Grobe Idee - Sie könnten dafür Middleware verwenden. Diese Middleware kann Anforderungen bearbeiten und ein Signal auslösen, wenn die entsprechende URL angefordert wird. Es könnte auch Reaktionen und Feuersignale verarbeiten, wenn die gegebene Aktion tatsächlich erfolgreich war.

0

eine schnelle Lösung dafür wäre, in der _ _ init _ _.py Ihrer App den folgenden Code einzufügen:

from Django.contrib.auth.signals import user_logged_in
from Django.dispatch import receiver


@receiver(user_logged_in)
def on_login(sender, user, request, **kwargs):
    print('User just logged in....')
0
Rui Lima